Merge "libcameraservice: Allow media server to disconnect camera even unlocked" am: a68b10a49b
am: f615179ee4
* commit 'f615179ee48bb11a27426d60f76845764cf00f75':
libcameraservice: Allow media server to disconnect camera even unlocked
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index 9bf3134..cd3b84c 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -136,6 +136,15 @@
return c->setPreviewTarget(bufferProducer);
}
+status_t Camera::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer)
+{
+ ALOGV("setVideoTarget(%p)", bufferProducer.get());
+ sp <ICamera> c = mCamera;
+ if (c == 0) return NO_INIT;
+ ALOGD_IF(bufferProducer == 0, "app passed NULL video surface");
+ return c->setVideoTarget(bufferProducer);
+}
+
// start preview mode
status_t Camera::startPreview()
{
@@ -145,13 +154,12 @@
return c->startPreview();
}
-status_t Camera::storeMetaDataInBuffers(bool enabled)
+status_t Camera::setVideoBufferMode(int32_t videoBufferMode)
{
- ALOGV("storeMetaDataInBuffers: %s",
- enabled? "true": "false");
+ ALOGV("setVideoBufferMode: %d", videoBufferMode);
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
- return c->storeMetaDataInBuffers(enabled);
+ return c->setVideoBufferMode(videoBufferMode);
}
// start recording mode, must call setPreviewTarget first
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 9943be6..cce5a9a 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -48,7 +48,8 @@
STOP_RECORDING,
RECORDING_ENABLED,
RELEASE_RECORDING_FRAME,
- STORE_META_DATA_IN_BUFFERS,
+ SET_VIDEO_BUFFER_MODE,
+ SET_VIDEO_BUFFER_TARGET,
};
class BpCamera: public BpInterface<ICamera>
@@ -151,13 +152,13 @@
remote()->transact(RELEASE_RECORDING_FRAME, data, &reply);
}
- status_t storeMetaDataInBuffers(bool enabled)
+ status_t setVideoBufferMode(int32_t videoBufferMode)
{
- ALOGV("storeMetaDataInBuffers: %s", enabled? "true": "false");
+ ALOGV("setVideoBufferMode: %d", videoBufferMode);
Parcel data, reply;
data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
- data.writeInt32(enabled);
- remote()->transact(STORE_META_DATA_IN_BUFFERS, data, &reply);
+ data.writeInt32(videoBufferMode);
+ remote()->transact(SET_VIDEO_BUFFER_MODE, data, &reply);
return reply.readInt32();
}
@@ -268,6 +269,17 @@
remote()->transact(UNLOCK, data, &reply);
return reply.readInt32();
}
+
+ status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer)
+ {
+ ALOGV("setVideoTarget");
+ Parcel data, reply;
+ data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
+ sp<IBinder> b(IInterface::asBinder(bufferProducer));
+ data.writeStrongBinder(b);
+ remote()->transact(SET_VIDEO_BUFFER_TARGET, data, &reply);
+ return reply.readInt32();
+ }
};
IMPLEMENT_META_INTERFACE(Camera, "android.hardware.ICamera");
@@ -339,11 +351,11 @@
releaseRecordingFrame(mem);
return NO_ERROR;
} break;
- case STORE_META_DATA_IN_BUFFERS: {
- ALOGV("STORE_META_DATA_IN_BUFFERS");
+ case SET_VIDEO_BUFFER_MODE: {
+ ALOGV("SET_VIDEO_BUFFER_MODE");
CHECK_INTERFACE(ICamera, data, reply);
- bool enabled = data.readInt32();
- reply->writeInt32(storeMetaDataInBuffers(enabled));
+ int32_t mode = data.readInt32();
+ reply->writeInt32(setVideoBufferMode(mode));
return NO_ERROR;
} break;
case PREVIEW_ENABLED: {
@@ -415,6 +427,14 @@
reply->writeInt32(unlock());
return NO_ERROR;
} break;
+ case SET_VIDEO_BUFFER_TARGET: {
+ ALOGV("SET_VIDEO_BUFFER_TARGET");
+ CHECK_INTERFACE(ICamera, data, reply);
+ sp<IGraphicBufferProducer> st =
+ interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
+ reply->writeInt32(setVideoTarget(st));
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/camera/tests/CameraBinderTests.cpp b/camera/tests/CameraBinderTests.cpp
index 572fb72..78a1b58 100644
--- a/camera/tests/CameraBinderTests.cpp
+++ b/camera/tests/CameraBinderTests.cpp
@@ -160,6 +160,7 @@
virtual void onDeviceError(CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras) {
+ (void) resultExtras;
ALOGE("%s: onDeviceError occurred with: %d", __FUNCTION__, static_cast<int>(errorCode));
Mutex::Autolock l(mLock);
mError = true;
@@ -177,6 +178,8 @@
virtual void onCaptureStarted(const CaptureResultExtras& resultExtras,
int64_t timestamp) {
+ (void) resultExtras;
+ (void) timestamp;
Mutex::Autolock l(mLock);
mLastStatus = RUNNING;
mStatusesHit.push_back(mLastStatus);
@@ -186,6 +189,8 @@
virtual void onResultReceived(const CameraMetadata& metadata,
const CaptureResultExtras& resultExtras) {
+ (void) metadata;
+ (void) resultExtras;
Mutex::Autolock l(mLock);
mLastStatus = SENT_RESULT;
mStatusesHit.push_back(mLastStatus);
@@ -193,6 +198,7 @@
}
virtual void onPrepared(int streamId) {
+ (void) streamId;
Mutex::Autolock l(mLock);
mLastStatus = PREPARED;
mStatusesHit.push_back(mLastStatus);
@@ -465,6 +471,7 @@
callbacks->clearStatus();
int requestId3 = device->submitRequestList(requestList, /*streaming*/false,
/*out*/&lastFrameNumber);
+ EXPECT_LE(0, requestId3);
EXPECT_TRUE(callbacks->waitForStatus(TestCameraDeviceCallbacks::SENT_RESULT));
EXPECT_TRUE(callbacks->waitForIdle());
EXPECT_LE(lastFrameNumberPrev, lastFrameNumber);
diff --git a/cmds/screenrecord/FrameOutput.cpp b/cmds/screenrecord/FrameOutput.cpp
index bef74f5..ee7ace6 100644
--- a/cmds/screenrecord/FrameOutput.cpp
+++ b/cmds/screenrecord/FrameOutput.cpp
@@ -74,7 +74,7 @@
GL_TEXTURE_EXTERNAL_OES, true, false);
mGlConsumer->setName(String8("virtual display"));
mGlConsumer->setDefaultBufferSize(width, height);
- mGlConsumer->setDefaultMaxBufferCount(5);
+ producer->setMaxDequeuedBufferCount(4);
mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
mGlConsumer->setFrameAvailableListener(this);
diff --git a/cmds/screenrecord/Overlay.cpp b/cmds/screenrecord/Overlay.cpp
index c659170..9fd192c 100644
--- a/cmds/screenrecord/Overlay.cpp
+++ b/cmds/screenrecord/Overlay.cpp
@@ -176,7 +176,7 @@
GL_TEXTURE_EXTERNAL_OES, true, false);
mGlConsumer->setName(String8("virtual display"));
mGlConsumer->setDefaultBufferSize(width, height);
- mGlConsumer->setDefaultMaxBufferCount(5);
+ mProducer->setMaxDequeuedBufferCount(4);
mGlConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_TEXTURE);
mGlConsumer->setFrameAvailableListener(this);
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk
index 20c0094..05fa34f 100644
--- a/cmds/stagefright/Android.mk
+++ b/cmds/stagefright/Android.mk
@@ -35,7 +35,7 @@
record.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libstagefright_foundation
+ libstagefright libmedia liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -59,7 +59,7 @@
recordvideo.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libstagefright_foundation
+ libstagefright libmedia liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
@@ -84,7 +84,7 @@
audioloop.cpp
LOCAL_SHARED_LIBRARIES := \
- libstagefright liblog libutils libbinder libstagefright_foundation
+ libstagefright libmedia liblog libutils libbinder libstagefright_foundation
LOCAL_C_INCLUDES:= \
frameworks/av/media/libstagefright \
diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp
index 6e9e6ec..db0c12d 100644
--- a/cmds/stagefright/audioloop.cpp
+++ b/cmds/stagefright/audioloop.cpp
@@ -109,7 +109,7 @@
meta->setInt32(kKeyMaxInputSize, maxInputSize);
}
- sp<MediaSource> encoder = OMXCodec::Create(
+ sp<IMediaSource> encoder = OMXCodec::Create(
client.interface(),
meta, true /* createEncoder */,
source);
@@ -128,7 +128,7 @@
writer->stop();
} else {
// otherwise decode to speaker
- sp<MediaSource> decoder = OMXCodec::Create(
+ sp<IMediaSource> decoder = OMXCodec::Create(
client.interface(),
meta, false /* createEncoder */,
encoder);
diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp
index 594c933..cd9c8dc 100644
--- a/cmds/stagefright/record.cpp
+++ b/cmds/stagefright/record.cpp
@@ -325,7 +325,7 @@
encMeta->setInt32(kKeyMaxInputSize, 8192);
encMeta->setInt32(kKeyBitRate, kAudioBitRate);
- sp<MediaSource> encoder =
+ sp<IMediaSource> encoder =
OMXCodec::Create(client.interface(), encMeta, true, audioSource);
encoder->start();
diff --git a/cmds/stagefright/recordvideo.cpp b/cmds/stagefright/recordvideo.cpp
index 2ad40bd..05b50be 100644
--- a/cmds/stagefright/recordvideo.cpp
+++ b/cmds/stagefright/recordvideo.cpp
@@ -299,7 +299,7 @@
enc_meta->setInt32(kKeyVideoProfile, profile);
}
- sp<MediaSource> encoder =
+ sp<IMediaSource> encoder =
OMXCodec::Create(
client.interface(), enc_meta, true /* createEncoder */, source,
0, preferSoftwareCodec ? OMXCodec::kPreferSoftwareCodecs : 0);
diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp
index 0d64d2f..1a4bf08 100644
--- a/cmds/stagefright/sf2.cpp
+++ b/cmds/stagefright/sf2.cpp
@@ -118,7 +118,7 @@
DataSource::CreateFromURI(
NULL /* httpService */, mURI.c_str());
- sp<MediaExtractor> extractor =
+ sp<IMediaExtractor> extractor =
MediaExtractor::Create(dataSource);
for (size_t i = 0; i < extractor->countTracks(); ++i) {
@@ -264,7 +264,7 @@
sp<Surface> mSurface;
bool mRenderToSurface;
sp<ACodec> mCodec;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
bool mIsVorbis;
Vector<sp<ABuffer> > mCSD;
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index a9c6eda..3e4df0f 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -67,6 +67,7 @@
static bool gPlaybackAudio;
static bool gWriteMP4;
static bool gDisplayHistogram;
+static bool showProgress = true;
static String8 gWriteMP4Filename;
static sp<ANativeWindow> gSurface;
@@ -130,7 +131,7 @@
}
}
-static void dumpSource(const sp<MediaSource> &source, const String8 &filename) {
+static void dumpSource(const sp<IMediaSource> &source, const String8 &filename) {
FILE *out = fopen(filename.string(), "wb");
CHECK_EQ((status_t)OK, source->start());
@@ -163,13 +164,13 @@
out = NULL;
}
-static void playSource(OMXClient *client, sp<MediaSource> &source) {
+static void playSource(OMXClient *client, sp<IMediaSource> &source) {
sp<MetaData> meta = source->getFormat();
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
- sp<MediaSource> rawSource;
+ sp<IMediaSource> rawSource;
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_RAW, mime)) {
rawSource = source;
} else {
@@ -338,7 +339,7 @@
decodeTimesUs.push(delayDecodeUs);
}
- if ((n++ % 16) == 0) {
+ if (showProgress && (n++ % 16) == 0) {
printf(".");
fflush(stdout);
}
@@ -364,8 +365,10 @@
}
}
- printf("$");
- fflush(stdout);
+ if (showProgress) {
+ printf("$");
+ fflush(stdout);
+ }
options.setSeekTo(0);
}
@@ -397,7 +400,7 @@
////////////////////////////////////////////////////////////////////////////////
struct DetectSyncSource : public MediaSource {
- DetectSyncSource(const sp<MediaSource> &source);
+ DetectSyncSource(const sp<IMediaSource> &source);
virtual status_t start(MetaData *params = NULL);
virtual status_t stop();
@@ -414,14 +417,14 @@
OTHER,
};
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
StreamType mStreamType;
bool mSawFirstIDRFrame;
DISALLOW_EVIL_CONSTRUCTORS(DetectSyncSource);
};
-DetectSyncSource::DetectSyncSource(const sp<MediaSource> &source)
+DetectSyncSource::DetectSyncSource(const sp<IMediaSource> &source)
: mSource(source),
mStreamType(OTHER),
mSawFirstIDRFrame(false) {
@@ -503,7 +506,7 @@
////////////////////////////////////////////////////////////////////////////////
static void writeSourcesToMP4(
- Vector<sp<MediaSource> > &sources, bool syncInfoPresent) {
+ Vector<sp<IMediaSource> > &sources, bool syncInfoPresent) {
#if 0
sp<MPEG4Writer> writer =
new MPEG4Writer(gWriteMP4Filename.string());
@@ -521,7 +524,7 @@
writer->setMaxFileDuration(60000000ll);
for (size_t i = 0; i < sources.size(); ++i) {
- sp<MediaSource> source = sources.editItemAt(i);
+ sp<IMediaSource> source = sources.editItemAt(i);
CHECK_EQ(writer->addSource(
syncInfoPresent ? source : new DetectSyncSource(source)),
@@ -538,7 +541,7 @@
writer->stop();
}
-static void performSeekTest(const sp<MediaSource> &source) {
+static void performSeekTest(const sp<IMediaSource> &source) {
CHECK_EQ((status_t)OK, source->start());
int64_t durationUs;
@@ -612,6 +615,7 @@
fprintf(stderr, " -k seek test\n");
fprintf(stderr, " -x display a histogram of decoding times/fps "
"(video only)\n");
+ fprintf(stderr, " -q don't show progress indicator\n");
fprintf(stderr, " -S allocate buffers from a surface\n");
fprintf(stderr, " -T allocate buffers from a surface texture\n");
fprintf(stderr, " -d(ump) output_filename (raw stream data to a file)\n");
@@ -687,7 +691,7 @@
sp<ALooper> looper;
int res;
- while ((res = getopt(argc, argv, "han:lm:b:ptsrow:kxSTd:D:")) >= 0) {
+ while ((res = getopt(argc, argv, "haqn:lm:b:ptsrow:kxSTd:D:")) >= 0) {
switch (res) {
case 'a':
{
@@ -695,6 +699,12 @@
break;
}
+ case 'q':
+ {
+ showProgress = false;
+ break;
+ }
+
case 'd':
{
dumpStream = true;
@@ -985,8 +995,8 @@
isJPEG = true;
}
- Vector<sp<MediaSource> > mediaSources;
- sp<MediaSource> mediaSource;
+ Vector<sp<IMediaSource> > mediaSources;
+ sp<IMediaSource> mediaSource;
if (isJPEG) {
mediaSource = new JPEGSource(dataSource);
@@ -1005,7 +1015,7 @@
mediaSources.push(mediaSource);
}
} else {
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
fprintf(stderr, "could not create extractor.\n");
@@ -1016,7 +1026,10 @@
if (meta != NULL) {
const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ fprintf(stderr, "extractor did not provide MIME type.\n");
+ return -1;
+ }
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
syncInfoPresent = false;
@@ -1029,7 +1042,7 @@
bool haveAudio = false;
bool haveVideo = false;
for (size_t i = 0; i < numTracks; ++i) {
- sp<MediaSource> source = extractor->getTrack(i);
+ sp<IMediaSource> source = extractor->getTrack(i);
const char *mime;
CHECK(source->getFormat()->findCString(
@@ -1059,6 +1072,9 @@
meta = extractor->getTrackMetaData(
i, MediaExtractor::kIncludeExtensiveMetaData);
+ if (meta == NULL) {
+ break;
+ }
const char *mime;
meta->findCString(kKeyMIMEType, &mime);
@@ -1100,7 +1116,7 @@
OMXClient client;
CHECK_EQ(client.connect(), (status_t)OK);
- sp<MediaSource> decSource =
+ sp<IMediaSource> decSource =
OMXCodec::Create(
client.interface(),
mediaSource->getFormat(),
diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp
index 1a40e53..bca3832 100644
--- a/cmds/stagefright/stream.cpp
+++ b/cmds/stagefright/stream.cpp
@@ -165,7 +165,7 @@
CHECK(dataSource != NULL);
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
CHECK(extractor != NULL);
mWriter = new MPEG2TSWriter(
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
index 53cbf80..6666343 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.cpp
@@ -33,7 +33,7 @@
// decrypted data. In theory, the output size can be larger than the input
// size, but in practice this will never happen for AES-CTR.
ssize_t CryptoPlugin::decrypt(bool secure, const KeyId keyId, const Iv iv,
- Mode mode, const void* srcPtr,
+ Mode mode, const Pattern &pattern, const void* srcPtr,
const SubSample* subSamples, size_t numSubSamples,
void* dstPtr, AString* errorDetailMsg) {
if (secure) {
diff --git a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
index fd38f28..de84c36 100644
--- a/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/CryptoPlugin.h
@@ -44,7 +44,7 @@
virtual ssize_t decrypt(
bool secure, const KeyId keyId, const Iv iv,
- Mode mode, const void* srcPtr,
+ Mode mode, const Pattern &pattern, const void* srcPtr,
const SubSample* subSamples, size_t numSubSamples,
void* dstPtr, android::AString* errorDetailMsg);
diff --git a/drm/mediadrm/plugins/clearkey/DrmPlugin.h b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
index ba4aefe..9095045 100644
--- a/drm/mediadrm/plugins/clearkey/DrmPlugin.h
+++ b/drm/mediadrm/plugins/clearkey/DrmPlugin.h
@@ -105,10 +105,6 @@
return android::ERROR_DRM_CANNOT_HANDLE;
}
- virtual status_t unprovisionDevice() {
- return android::ERROR_DRM_CANNOT_HANDLE;
- }
-
virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops) {
UNUSED(secureStops);
return android::ERROR_DRM_CANNOT_HANDLE;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
index 851ad2c..1e80f8e 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.cpp
@@ -312,12 +312,6 @@
return OK;
}
- status_t MockDrmPlugin::unprovisionDevice()
- {
- ALOGD("MockDrmPlugin::unprovisionDevice()");
- return OK;
- }
-
status_t MockDrmPlugin::getSecureStop(Vector<uint8_t> const & /* ssid */,
Vector<uint8_t> & secureStop)
{
@@ -798,15 +792,17 @@
ssize_t
MockCryptoPlugin::decrypt(bool secure, const uint8_t key[16], const uint8_t iv[16],
- Mode mode, const void *srcPtr, const SubSample *subSamples,
- size_t numSubSamples, void *dstPtr, AString * /* errorDetailMsg */)
+ Mode mode, const Pattern &pattern, const void *srcPtr,
+ const SubSample *subSamples, size_t numSubSamples,
+ void *dstPtr, AString * /* errorDetailMsg */)
{
- ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, src=%p, "
+ ALOGD("MockCryptoPlugin::decrypt(secure=%d, key=%s, iv=%s, mode=%d, "
+ "pattern:{encryptBlocks=%d, skipBlocks=%d} src=%p, "
"subSamples=%s, dst=%p)",
(int)secure,
arrayToString(key, sizeof(key)).string(),
arrayToString(iv, sizeof(iv)).string(),
- (int)mode, srcPtr,
+ (int)mode, pattern.mEncryptBlocks, pattern.mSkipBlocks, srcPtr,
subSamplesToString(subSamples, numSubSamples).string(),
dstPtr);
return OK;
diff --git a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
index d0f2ddb..40d4e84 100644
--- a/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
+++ b/drm/mediadrm/plugins/mock/MockDrmCryptoPlugin.h
@@ -86,8 +86,6 @@
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey);
- status_t unprovisionDevice();
-
status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
status_t releaseSecureStops(Vector<uint8_t> const &ssRelease);
@@ -161,7 +159,7 @@
ssize_t decrypt(bool secure,
const uint8_t key[16], const uint8_t iv[16],
- Mode mode, const void *srcPtr,
+ Mode mode, const Pattern &pattern, const void *srcPtr,
const SubSample *subSamples, size_t numSubSamples,
void *dstPtr, AString *errorDetailMsg);
private:
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 2b60842..f7bf29c 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -126,8 +126,15 @@
// send command to camera driver
status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
- // tell camera hal to store meta data or real YUV in video buffers.
- status_t storeMetaDataInBuffers(bool enabled);
+ // Tell camera how to pass video buffers. videoBufferMode is one of VIDEO_BUFFER_MODE_*.
+ // Returns OK if the specified video buffer mode is supported. If videoBufferMode is
+ // VIDEO_BUFFER_MODE_BUFFER_QUEUE, setVideoTarget() must be called before starting
+ // video recording.
+ status_t setVideoBufferMode(int32_t videoBufferMode);
+
+ // Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE
+ // mode.
+ status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
void setListener(const sp<CameraListener>& listener);
void setRecordingProxyListener(const sp<ICameraRecordingProxyListener>& listener);
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index b025735..e35c3a4 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -36,6 +36,15 @@
* Keep up-to-date with ICamera.aidl in frameworks/base
*/
public:
+ enum {
+ // Pass real YUV data in video buffers through ICameraClient.dataCallbackTimestamp().
+ VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV = 0,
+ // Pass metadata in video buffers through ICameraClient.dataCallbackTimestamp().
+ VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA = 1,
+ // Pass video buffers through IGraphicBufferProducer set with setVideoTarget().
+ VIDEO_BUFFER_MODE_BUFFER_QUEUE = 2,
+ };
+
DECLARE_META_INTERFACE(Camera);
virtual void disconnect() = 0;
@@ -109,8 +118,16 @@
// send command to camera driver
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
- // tell the camera hal to store meta data or real YUV data in video buffers.
- virtual status_t storeMetaDataInBuffers(bool enabled) = 0;
+
+ // Tell camera how to pass video buffers. videoBufferMode is one of VIDEO_BUFFER_MODE_*.
+ // Returns OK if the specified video buffer mode is supported. If videoBufferMode is
+ // VIDEO_BUFFER_MODE_BUFFER_QUEUE, setVideoTarget() must be called before starting video
+ // recording.
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode) = 0;
+
+ // Set the video buffer producer for camera to use in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ virtual status_t setVideoTarget(
+ const sp<IGraphicBufferProducer>& bufferProducer) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h
index feed402..ff07b08 100644
--- a/include/media/AudioPolicy.h
+++ b/include/media/AudioPolicy.h
@@ -91,6 +91,12 @@
uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
};
+
+// definitions for audio recording configuration updates
+// which update type is reported
+#define RECORD_CONFIG_EVENT_START 1
+#define RECORD_CONFIG_EVENT_STOP 0
+
}; // namespace android
#endif // ANDROID_AUDIO_POLICY_H
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index c4c7b0e..c47a4e7 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -20,6 +20,7 @@
#include <cutils/sched_policy.h>
#include <media/AudioSystem.h>
#include <media/IAudioRecord.h>
+#include <media/Modulo.h>
#include <utils/threads.h>
namespace android {
@@ -526,7 +527,7 @@
// caller must hold lock on mLock for all _l methods
- status_t openRecord_l(size_t epoch, const String16& opPackageName);
+ status_t openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName);
// FIXME enum is faster than strcmp() for parameter 'from'
status_t restoreRecord_l(const char *from);
@@ -556,9 +557,9 @@
bool mRetryOnPartialBuffer; // sleep and retry after partial obtainBuffer()
uint32_t mObservedSequence; // last observed value of mSequence
- uint32_t mMarkerPosition; // in wrapping (overflow) frame units
+ Modulo<uint32_t> mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
- uint32_t mNewPosition; // in frames
+ Modulo<uint32_t> mNewPosition; // in frames
uint32_t mUpdatePeriod; // in frames, zero means no EVENT_NEW_POS
status_t mStatus;
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 26a0bb2..2f95b90 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -31,6 +31,7 @@
typedef void (*audio_error_callback)(status_t err);
typedef void (*dynamic_policy_callback)(int event, String8 regId, int val);
+typedef void (*record_config_callback)(int event, int session, int source);
class IAudioFlinger;
class IAudioPolicyService;
@@ -92,6 +93,7 @@
static void setErrorCallback(audio_error_callback cb);
static void setDynPolicyCallback(dynamic_policy_callback cb);
+ static void setRecordConfigCallback(record_config_callback);
// helper function to obtain AudioFlinger service handle
static const sp<IAudioFlinger> get_audio_flinger();
@@ -319,6 +321,8 @@
audio_io_handle_t *handle);
static status_t stopAudioSource(audio_io_handle_t handle);
+ static status_t setMasterMono(bool mono);
+ static status_t getMasterMono(bool *mono);
// ----------------------------------------------------------------------------
@@ -419,6 +423,8 @@
virtual void onAudioPortListUpdate();
virtual void onAudioPatchListUpdate();
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
private:
Mutex mLock;
@@ -438,6 +444,7 @@
static sp<IAudioFlinger> gAudioFlinger;
static audio_error_callback gAudioErrorCallback;
static dynamic_policy_callback gDynPolicyCallback;
+ static record_config_callback gRecordConfigCallback;
static size_t gInBuffSize;
// previous parameters for recording buffer size queries
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index e02f1b7..fe4611c 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -22,6 +22,7 @@
#include <media/AudioTimestamp.h>
#include <media/IAudioTrack.h>
#include <media/AudioResamplerPublic.h>
+#include <media/Modulo.h>
#include <utils/threads.h>
namespace android {
@@ -798,7 +799,7 @@
{ return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
// increment mPosition by the delta of mServer, and return new value of mPosition
- uint32_t updateAndGetPosition_l();
+ Modulo<uint32_t> updateAndGetPosition_l();
// check sample rate and speed is compatible with AudioTrack
bool isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const;
@@ -885,19 +886,19 @@
bool mRetryOnPartialBuffer; // sleep and retry after partial obtainBuffer()
uint32_t mObservedSequence; // last observed value of mSequence
- uint32_t mMarkerPosition; // in wrapping (overflow) frame units
+ Modulo<uint32_t> mMarkerPosition; // in wrapping (overflow) frame units
bool mMarkerReached;
- uint32_t mNewPosition; // in frames
+ Modulo<uint32_t> mNewPosition; // in frames
uint32_t mUpdatePeriod; // in frames, zero means no EVENT_NEW_POS
- uint32_t mServer; // in frames, last known mProxy->getPosition()
+ Modulo<uint32_t> mServer; // in frames, last known mProxy->getPosition()
// which is count of frames consumed by server,
// reset by new IAudioTrack,
// whether it is reset by stop() is TBD
- uint32_t mPosition; // in frames, like mServer except continues
+ Modulo<uint32_t> mPosition; // in frames, like mServer except continues
// monotonically after new IAudioTrack,
// and could be easily widened to uint64_t
- uint32_t mReleased; // in frames, count of frames released to server
+ Modulo<uint32_t> mReleased; // count of frames released to server
// but not necessarily consumed by server,
// reset by stop() but continues monotonically
// after new IAudioTrack to restore mPosition,
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 6b93f6f..ceca71a 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -165,6 +165,9 @@
const audio_attributes_t *attributes,
audio_io_handle_t *handle) = 0;
virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+ virtual status_t setMasterMono(bool mono) = 0;
+ virtual status_t getMasterMono(bool *mono) = 0;
};
diff --git a/include/media/IAudioPolicyServiceClient.h b/include/media/IAudioPolicyServiceClient.h
index a7f2cc3..e8fd39f 100644
--- a/include/media/IAudioPolicyServiceClient.h
+++ b/include/media/IAudioPolicyServiceClient.h
@@ -37,6 +37,9 @@
virtual void onAudioPatchListUpdate() = 0;
// Notifies a change in the mixing state of a specific mix in a dynamic audio policy
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
+ // Notifies a change of audio recording configuration
+ virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) = 0;
};
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index ea316de..5e324ad 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -51,6 +51,7 @@
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
diff --git a/include/media/IDrm.h b/include/media/IDrm.h
index 9449beb6..fd51fd0 100644
--- a/include/media/IDrm.h
+++ b/include/media/IDrm.h
@@ -71,8 +71,6 @@
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey) = 0;
- virtual status_t unprovisionDevice() = 0;
-
virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) = 0;
virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop) = 0;
diff --git a/include/media/IMediaExtractor.h b/include/media/IMediaExtractor.h
new file mode 100644
index 0000000..9f7a719
--- /dev/null
+++ b/include/media/IMediaExtractor.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMEDIA_EXTRACTOR_BASE_H_
+
+#define IMEDIA_EXTRACTOR_BASE_H_
+
+#include <media/IMediaSource.h>
+
+namespace android {
+
+class MetaData;
+
+class IMediaExtractor : public IInterface {
+public:
+ DECLARE_META_INTERFACE(MediaExtractor);
+
+ virtual size_t countTracks() = 0;
+ virtual sp<IMediaSource> getTrack(size_t index) = 0;
+
+ enum GetTrackMetaDataFlags {
+ kIncludeExtensiveMetaData = 1
+ };
+ virtual sp<MetaData> getTrackMetaData(
+ size_t index, uint32_t flags = 0) = 0;
+
+ // Return container specific meta-data. The default implementation
+ // returns an empty metadata object.
+ virtual sp<MetaData> getMetaData() = 0;
+
+ enum Flags {
+ CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
+ CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
+ CAN_PAUSE = 4,
+ CAN_SEEK = 8, // the "seek bar"
+ };
+
+ // If subclasses do _not_ override this, the default is
+ // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+ virtual uint32_t flags() const = 0;
+
+ // for DRM
+ virtual void setDrmFlag(bool flag) = 0;
+ virtual bool getDrmFlag() = 0;
+ virtual char* getDrmTrackInfo(size_t trackID, int *len) = 0;
+ virtual void setUID(uid_t uid) = 0;
+
+ virtual const char * name() = 0;
+};
+
+
+class BnMediaExtractor: public BnInterface<IMediaExtractor>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+
+} // namespace android
+
+#endif // IMEDIA_EXTRACTOR_BASE_H_
diff --git a/include/media/IMediaExtractorService.h b/include/media/IMediaExtractorService.h
new file mode 100644
index 0000000..4d7b317
--- /dev/null
+++ b/include/media/IMediaExtractorService.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_IMEDIAEXTRACTORSERVICE_H
+#define ANDROID_IMEDIAEXTRACTORSERVICE_H
+
+#include <binder/IInterface.h>
+#include <binder/IMemory.h>
+#include <binder/Parcel.h>
+#include <media/IDataSource.h>
+#include <media/IMediaExtractor.h>
+
+namespace android {
+
+class IMediaExtractorService: public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(MediaExtractorService);
+
+ virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) = 0;
+
+};
+
+class BnMediaExtractorService: public BnInterface<IMediaExtractorService>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // ANDROID_IMEDIAEXTRACTORSERVICE_H
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 77ed5d3..caa6592 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -53,6 +53,8 @@
virtual status_t start() = 0;
virtual status_t stop() = 0;
virtual status_t reset() = 0;
+ virtual status_t pause() = 0;
+ virtual status_t resume() = 0;
virtual status_t init() = 0;
virtual status_t close() = 0;
virtual status_t release() = 0;
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
new file mode 100644
index 0000000..1420120
--- /dev/null
+++ b/include/media/IMediaSource.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef IMEDIA_SOURCE_BASE_H_
+
+#define IMEDIA_SOURCE_BASE_H_
+
+#include <binder/IInterface.h>
+#include <media/stagefright/MediaErrors.h>
+
+namespace android {
+
+struct MediaSource;
+class MetaData;
+class MediaBuffer;
+
+class IMediaSource : public IInterface {
+public:
+ DECLARE_META_INTERFACE(MediaSource);
+
+ // To be called before any other methods on this object, except
+ // getFormat().
+ virtual status_t start(MetaData *params = NULL) = 0;
+
+ // Any blocking read call returns immediately with a result of NO_INIT.
+ // It is an error to call any methods other than start after this call
+ // returns. Any buffers the object may be holding onto at the time of
+ // the stop() call are released.
+ // Also, it is imperative that any buffers output by this object and
+ // held onto by callers be released before a call to stop() !!!
+ virtual status_t stop() = 0;
+
+ // Returns the format of the data output by this media source.
+ virtual sp<MetaData> getFormat() = 0;
+
+ // Options that modify read() behaviour. The default is to
+ // a) not request a seek
+ // b) not be late, i.e. lateness_us = 0
+ struct ReadOptions {
+ enum SeekMode {
+ SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST,
+ };
+
+ ReadOptions();
+
+ // Reset everything back to defaults.
+ void reset();
+
+ void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
+ void clearSeekTo();
+ bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
+
+ void setLateBy(int64_t lateness_us);
+ int64_t getLateBy() const;
+
+ void setNonBlocking();
+ void clearNonBlocking();
+ bool getNonBlocking() const;
+
+ private:
+ enum Options {
+ kSeekTo_Option = 1,
+ };
+
+ uint32_t mOptions;
+ int64_t mSeekTimeUs;
+ SeekMode mSeekMode;
+ int64_t mLatenessUs;
+ bool mNonBlocking;
+ };
+
+ // Returns a new buffer of data. Call blocks until a
+ // buffer is available, an error is encountered of the end of the stream
+ // is reached.
+ // End of stream is signalled by a result of ERROR_END_OF_STREAM.
+ // A result of INFO_FORMAT_CHANGED indicates that the format of this
+ // MediaSource has changed mid-stream, the client can continue reading
+ // but should be prepared for buffers of the new configuration.
+ virtual status_t read(
+ MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
+
+ // Causes this source to suspend pulling data from its upstream source
+ // until a subsequent read-with-seek. Currently only supported by
+ // OMXCodec.
+ virtual status_t pause() = 0;
+
+ // The consumer of this media source requests that the given buffers
+ // are to be returned exclusively in response to read calls.
+ // This will be called after a successful start() and before the
+ // first read() call.
+ // Callee assumes ownership of the buffers if no error is returned.
+ virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) = 0;
+
+};
+
+class BnMediaSource: public BnInterface<IMediaSource>
+{
+public:
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags = 0);
+
+ virtual status_t pause() {
+ return ERROR_UNSUPPORTED;
+ }
+
+ virtual status_t setBuffers(const Vector<MediaBuffer *> & /* buffers */) {
+ return ERROR_UNSUPPORTED;
+ }
+};
+
+
+} // namespace android
+
+#endif // IMEDIA_SOURCE_BASE_H_
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index de82554..9e5056f 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -99,6 +99,7 @@
virtual float msecsPerFrame() const = 0;
virtual status_t getPosition(uint32_t *position) const = 0;
virtual status_t getTimestamp(AudioTimestamp &ts) const = 0;
+ virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const = 0;
virtual status_t getFramesWritten(uint32_t *frameswritten) const = 0;
virtual int getSessionId() const = 0;
virtual audio_stream_type_t getAudioStreamType() const = 0;
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index d6cc4bb..c05d782 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -53,6 +53,8 @@
virtual status_t prepare() = 0;
virtual status_t start() = 0;
virtual status_t stop() = 0;
+ virtual status_t pause() = 0;
+ virtual status_t resume() = 0;
virtual status_t close() = 0;
virtual status_t reset() = 0;
virtual status_t getMaxAmplitude(int *max) = 0;
diff --git a/include/media/Modulo.h b/include/media/Modulo.h
new file mode 100644
index 0000000..23280ac
--- /dev/null
+++ b/include/media/Modulo.h
@@ -0,0 +1,220 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_MODULO_H
+#define ANDROID_MODULO_H
+
+namespace android {
+
+// Modulo class is used for intentionally wrapping variables such as
+// counters and timers.
+//
+// It may also be used for variables whose computation depends on the
+// associativity of addition or subtraction.
+//
+// Features:
+// 1) Modulo checks type sizes before performing operations to ensure
+// that the wrap points match. This is critical for safe modular arithmetic.
+// 2) Modulo returns Modulo types from arithmetic operations, thereby
+// avoiding unintentional use in a non-modular computation. A Modulo
+// type is converted to its base non-Modulo type through the value() function.
+// 3) Modulo separates out overflowable types from non-overflowable types.
+// A signed overflow is technically undefined in C and C++.
+// Modulo types do not participate in sanitization.
+// 4) Modulo comparisons are based on signed differences to account for wrap;
+// this is not the same as the direct comparison of values.
+// 5) Safe use of binary arithmetic operations relies on conversions of
+// signed operands to unsigned operands (which are modular arithmetic safe).
+// Conversions which are implementation-defined are assumed to use 2's complement
+// representation. (See A, B, C, D from the ISO/IEC FDIS 14882
+// Information technology — Programming languages — C++).
+//
+// A: ISO/IEC 14882:2011(E) p84 section 4.7 Integral conversions
+// (2) If the destination type is unsigned, the resulting value is the least unsigned
+// integer congruent to the source integer (modulo 2^n where n is the number of bits
+// used to represent the unsigned type). [ Note: In a two’s complement representation,
+// this conversion is conceptual and there is no change in the bit pattern (if there
+// is no truncation). — end note ]
+// (3) If the destination type is signed, the value is unchanged if it can be represented
+// in the destination type (and bit-field width); otherwise, the value is
+// implementation-defined.
+//
+// B: ISO/IEC 14882:2011(E) p88 section 5 Expressions
+// (9) Many binary operators that expect operands of arithmetic or enumeration type
+// cause conversions and yield result types in a similar way. The purpose is to
+// yield a common type, which is also the type of the result. This pattern is called
+// the usual arithmetic conversions, which are defined as follows:
+// [...]
+// Otherwise, if both operands have signed integer types or both have unsigned
+// integer types, the operand with the type of lesser integer conversion rank shall be
+// converted to the type of the operand with greater rank.
+// — Otherwise, if the operand that has unsigned integer type has rank greater than
+// or equal to the rank of the type of the other operand, the operand with signed
+// integer type shall be converted to the type of the operand with unsigned integer type.
+//
+// C: ISO/IEC 14882:2011(E) p86 section 4.13 Integer conversion rank
+// [...] The rank of long long int shall be greater than the rank of long int,
+// which shall be greater than the rank of int, which shall be greater than the
+// rank of short int, which shall be greater than the rank of signed char.
+// — The rank of any unsigned integer type shall equal the rank of the corresponding
+// signed integer type.
+//
+// D: ISO/IEC 14882:2011(E) p75 section 3.9.1 Fundamental types
+// [...] Unsigned integers, declared unsigned, shall obey the laws of arithmetic modulo
+// 2^n where n is the number of bits in the value representation of that particular
+// size of integer.
+//
+// Note:
+// Other libraries do exist for safe integer operations which can detect the
+// possibility of overflow (SafeInt from MS and safe-iop in android).
+// Signed safe computation is also possible from the art header safe_math.h.
+
+template <typename T> class Modulo {
+ T mValue;
+
+public:
+ typedef typename std::make_signed<T>::type signedT;
+ typedef typename std::make_unsigned<T>::type unsignedT;
+
+ Modulo() { } // intentionally uninitialized data
+ Modulo(const T &value) { mValue = value; }
+ const T & value() const { return mValue; } // not assignable
+ signedT signedValue() const { return mValue; }
+ unsignedT unsignedValue() const { return mValue; }
+ void getValue(T *value) const { *value = mValue; } // more type safe than value()
+
+ // modular operations valid only if size of T <= size of S.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator +=(const Modulo<S> &other) {
+ static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
+ mValue += other.unsignedValue();
+ return *this;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator -=(const Modulo<S> &other) {
+ static_assert(sizeof(T) <= sizeof(S), "argument size mismatch");
+ mValue -= other.unsignedValue();
+ return *this;
+ }
+
+ // modular operations resulting in a value valid only at the smaller of the two
+ // Modulo base type sizes, but we only allow equal sizes to avoid confusion.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator +(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue + other.unsignedValue());
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator -(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue - other.unsignedValue());
+ }
+
+ // modular operations that should be checked only at the smaller of
+ // the two type sizes, but we only allow equal sizes to avoid confusion.
+ //
+ // Caution: These relational and comparison operations are not equivalent to
+ // the base type operations.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator >(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) > 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator >=(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) >= 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator ==(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) == 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator <=(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) <= 0;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ bool operator <(const Modulo<S> &other) const {
+ static_assert(sizeof(T) == sizeof(S), "argument size mismatch");
+ return static_cast<signedT>(mValue - other.unsignedValue()) < 0;
+ }
+
+
+ // modular operations with a non-Modulo type allowed with wrapping
+ // because there should be no confusion as to the meaning.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator +=(const S &other) {
+ mValue += unsignedT(other);
+ return *this;
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ Modulo<T> operator -=(const S &other) {
+ mValue -= unsignedT(other);
+ return *this;
+ }
+
+ // modular operations with a non-Modulo type allowed with wrapping,
+ // but we restrict this only when size of T is greater than or equal to
+ // the size of S to avoid confusion with the nature of overflow.
+ //
+ // Use of this follows left-associative style.
+ //
+ // Note: a Modulo type may be promoted by using "differences" off of
+ // a larger sized type, but we do not automate this.
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator +(const S &other) const {
+ static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue + unsignedT(other));
+ }
+
+ template <typename S>
+ __attribute__((no_sanitize("integer")))
+ const Modulo<T> operator -(const S &other) const {
+ static_assert(sizeof(T) >= sizeof(S), "argument size mismatch");
+ return Modulo<T>(mValue - unsignedT(other));
+ }
+
+ // multiply is intentionally omitted, but it is a common operator in
+ // modular arithmetic.
+
+ // shift operations are intentionally omitted, but perhaps useful.
+ // For example, left-shifting a negative number is undefined in C++11.
+};
+
+} // namespace android
+
+#endif /* ANDROID_MODULO_H */
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 3fe749c..00df523 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -215,7 +215,6 @@
const KeyedVector<String8, String8> *headers);
status_t setDataSource(int fd, int64_t offset, int64_t length);
- status_t setDataSource(const sp<IStreamSource> &source);
status_t setDataSource(const sp<IDataSource> &source);
status_t setVideoSurfaceTexture(
const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 15ff82d..c375dff 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -233,6 +233,8 @@
status_t start();
status_t stop();
status_t reset();
+ status_t pause();
+ status_t resume();
status_t init();
status_t close();
status_t release();
diff --git a/include/media/stagefright/AACWriter.h b/include/media/stagefright/AACWriter.h
index aa60a19..a1f63d7 100644
--- a/include/media/stagefright/AACWriter.h
+++ b/include/media/stagefright/AACWriter.h
@@ -31,7 +31,7 @@
status_t initCheck() const;
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual bool reachedEOS();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop() { return reset(); }
@@ -48,7 +48,7 @@
int mFd;
status_t mInitCheck;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
bool mStarted;
volatile bool mPaused;
volatile bool mResumed;
diff --git a/include/media/stagefright/AMRWriter.h b/include/media/stagefright/AMRWriter.h
index b38be55..fbbdf2e 100644
--- a/include/media/stagefright/AMRWriter.h
+++ b/include/media/stagefright/AMRWriter.h
@@ -20,12 +20,12 @@
#include <stdio.h>
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaWriter.h>
#include <utils/threads.h>
namespace android {
-struct MediaSource;
class MetaData;
struct AMRWriter : public MediaWriter {
@@ -33,7 +33,7 @@
status_t initCheck() const;
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual bool reachedEOS();
virtual status_t start(MetaData *params = NULL);
virtual status_t stop() { return reset(); }
@@ -45,7 +45,7 @@
private:
int mFd;
status_t mInitCheck;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
bool mStarted;
volatile bool mPaused;
volatile bool mResumed;
diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h
index e0cd965..b495f91 100644
--- a/include/media/stagefright/AudioPlayer.h
+++ b/include/media/stagefright/AudioPlayer.h
@@ -18,6 +18,7 @@
#define AUDIO_PLAYER_H_
+#include <media/IMediaSource.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/TimeSource.h>
@@ -28,7 +29,6 @@
struct AudioPlaybackRate;
class AudioTrack;
struct AwesomePlayer;
-class MediaSource;
class AudioPlayer : public TimeSource {
public:
@@ -52,7 +52,7 @@
virtual ~AudioPlayer();
// Caller retains ownership of "source".
- void setSource(const sp<MediaSource> &source);
+ void setSource(const sp<IMediaSource> &source);
// Return time in us.
virtual int64_t getRealTimeUs();
@@ -81,7 +81,7 @@
private:
friend class VideoEditorAudioPlayer;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<AudioTrack> mAudioTrack;
MediaBuffer *mInputBuffer;
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index 069e897..769adf8 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -23,6 +23,7 @@
#include <camera/ICamera.h>
#include <camera/ICameraRecordingProxyListener.h>
#include <camera/CameraParameters.h>
+#include <gui/BufferItemConsumer.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/String16.h>
@@ -122,6 +123,12 @@
virtual void signalBufferReturned(MediaBuffer* buffer);
protected:
+
+ /**
+ * The class for listening to BnCameraRecordingProxyListener. This is used to receive video
+ * buffers in VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV and VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA
+ * mode. When a frame is available, CameraSource::dataCallbackTimestamp() will be called.
+ */
class ProxyListener: public BnCameraRecordingProxyListener {
public:
ProxyListener(const sp<CameraSource>& source);
@@ -132,6 +139,28 @@
sp<CameraSource> mSource;
};
+ /**
+ * The class for listening to BufferQueue's onFrameAvailable. This is used to receive video
+ * buffers in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode. When a frame is available,
+ * CameraSource::processBufferQueueFrame() will be called.
+ */
+ class BufferQueueListener : public Thread, public BufferItemConsumer::FrameAvailableListener {
+ public:
+ BufferQueueListener(const sp<BufferItemConsumer> &consumer,
+ const sp<CameraSource> &cameraSource);
+ virtual void onFrameAvailable(const BufferItem& item);
+ virtual bool threadLoop();
+ private:
+ static const nsecs_t kFrameAvailableTimeout = 50000000; // 50ms
+
+ sp<BufferItemConsumer> mConsumer;
+ sp<CameraSource> mCameraSource;
+
+ Mutex mLock;
+ Condition mFrameAvailableSignal;
+ bool mFrameAvailable;
+ };
+
// isBinderAlive needs linkToDeath to work.
class DeathNotifier: public IBinder::DeathRecipient {
public:
@@ -204,11 +233,29 @@
int32_t mNumGlitches;
int64_t mGlitchDurationThresholdUs;
bool mCollectStats;
- bool mIsMetaDataStoredInVideoBuffers;
+
+ // The mode video buffers are received from camera. One of VIDEO_BUFFER_MODE_*.
+ int32_t mVideoBufferMode;
+
+ /**
+ * The following variables are used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ */
+ static const size_t kConsumerBufferCount = 8;
+ // Consumer and producer of the buffer queue between this class and camera.
+ sp<BufferItemConsumer> mVideoBufferConsumer;
+ sp<IGraphicBufferProducer> mVideoBufferProducer;
+ // Memory used to send the buffers to encoder, where sp<IMemory> stores VideoNativeMetadata.
+ sp<IMemoryHeap> mMemoryHeapBase;
+ List<sp<IMemory>> mMemoryBases;
+ // A mapping from ANativeWindowBuffer sent to encoder to BufferItem received from camera.
+ // This is protected by mLock.
+ KeyedVector<ANativeWindowBuffer*, BufferItem> mReceivedBufferItemMap;
+ sp<BufferQueueListener> mBufferQueueListener;
void releaseQueuedFrames();
void releaseOneRecordingFrame(const sp<IMemory>& frame);
-
+ // Process a buffer item received in BufferQueueListener.
+ void processBufferQueueFrame(const BufferItem& buffer);
status_t init(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId, const String16& clientName, uid_t clientUid,
@@ -219,6 +266,10 @@
int32_t cameraId, const String16& clientName, uid_t clientUid,
Size videoSize, int32_t frameRate, bool storeMetaDataInVideoBuffers);
+ // Initialize the buffer queue used in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ status_t initBufferQueue(uint32_t width, uint32_t height, uint32_t format,
+ android_dataspace dataSpace, uint32_t bufferCount);
+
status_t isCameraAvailable(const sp<ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy,
int32_t cameraId,
@@ -236,6 +287,10 @@
status_t checkFrameRate(const CameraParameters& params,
int32_t frameRate);
+ // Check if this frame should be skipped based on the frame's timestamp in microsecond.
+ // mLock must be locked before calling this function.
+ bool shouldSkipFrameLocked(int64_t timestampUs);
+
void stopCameraRecording();
status_t reset();
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
index 3d7960b..4516fb6 100644
--- a/include/media/stagefright/MPEG2TSWriter.h
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -34,7 +34,7 @@
void *cookie,
ssize_t (*write)(void *cookie, const void *data, size_t size));
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual status_t start(MetaData *param = NULL);
virtual status_t stop() { return reset(); }
virtual status_t pause();
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index a195fe8..a6901a8 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -20,6 +20,7 @@
#include <stdio.h>
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaWriter.h>
#include <utils/List.h>
#include <utils/threads.h>
@@ -28,7 +29,6 @@
class AMessage;
class MediaBuffer;
-class MediaSource;
class MetaData;
class MPEG4Writer : public MediaWriter {
@@ -39,7 +39,7 @@
// 1. No more than 2 tracks can be added
// 2. Only video or audio source can be added
// 3. No more than one video and/or one audio source can be added.
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
// Returns INVALID_OPERATION if there is no source or track.
virtual status_t start(MetaData *param = NULL);
diff --git a/include/media/stagefright/MediaBuffer.h b/include/media/stagefright/MediaBuffer.h
index c8a50e8..1e0c7d4 100644
--- a/include/media/stagefright/MediaBuffer.h
+++ b/include/media/stagefright/MediaBuffer.h
@@ -22,6 +22,7 @@
#include <pthread.h>
+#include <binder/MemoryDealer.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -93,6 +94,8 @@
private:
friend class MediaBufferGroup;
friend class OMXDecoder;
+ friend class BnMediaSource;
+ friend class BpMediaSource;
// For use by OMXDecoder, reference count must be 1, drop reference
// count to 0 without signalling the observer.
@@ -118,6 +121,7 @@
MediaBuffer(const MediaBuffer &);
MediaBuffer &operator=(const MediaBuffer &);
+ sp<IMemory> mMemory;
};
} // namespace android
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index cdfa159..93ffa93 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -119,6 +119,7 @@
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
int64_t presentationTimeUs,
uint32_t flags,
AString *errorDetailMsg = NULL);
diff --git a/include/media/stagefright/MediaCodecSource.h b/include/media/stagefright/MediaCodecSource.h
index 71f58a9..14b0072 100644
--- a/include/media/stagefright/MediaCodecSource.h
+++ b/include/media/stagefright/MediaCodecSource.h
@@ -47,6 +47,7 @@
bool isVideo() const { return mIsVideo; }
sp<IGraphicBufferProducer> getGraphicBufferProducer();
+ void setInputBufferTimeOffset(int64_t timeOffsetUs);
// MediaSource
virtual status_t start(MetaData *params = NULL);
@@ -75,6 +76,7 @@
kWhatStart,
kWhatStop,
kWhatPause,
+ kWhatSetInputBufferTimeOffset,
};
MediaCodecSource(
@@ -117,6 +119,7 @@
List<MediaBuffer *> mInputBufferQueue;
List<size_t> mAvailEncoderInputIndices;
List<int64_t> mDecodingTimeQueue; // decoding time (us) for video
+ int64_t mInputBufferTimeOffsetUs;
// audio drift time
int64_t mFirstSampleTimeUs;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index 183933a..6bf8c9e 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -18,7 +18,8 @@
#define MEDIA_EXTRACTOR_H_
-#include <utils/RefBase.h>
+#include <media/IMediaExtractor.h>
+#include <media/IMediaSource.h>
namespace android {
@@ -26,13 +27,15 @@
class MediaSource;
class MetaData;
-class MediaExtractor : public RefBase {
+class MediaExtractor : public BnMediaExtractor {
public:
- static sp<MediaExtractor> Create(
+ static sp<IMediaExtractor> Create(
+ const sp<DataSource> &source, const char *mime = NULL);
+ static sp<MediaExtractor> CreateFromService(
const sp<DataSource> &source, const char *mime = NULL);
virtual size_t countTracks() = 0;
- virtual sp<MediaSource> getTrack(size_t index) = 0;
+ virtual sp<IMediaSource> getTrack(size_t index) = 0;
enum GetTrackMetaDataFlags {
kIncludeExtensiveMetaData = 1
@@ -68,8 +71,10 @@
virtual void setUID(uid_t uid) {
}
+ virtual const char * name() { return "<unspecified>"; }
+
protected:
- MediaExtractor() : mIsDrm(false) {}
+ MediaExtractor();
virtual ~MediaExtractor() {}
private:
diff --git a/include/media/stagefright/MediaSource.h b/include/media/stagefright/MediaSource.h
index a653db9..78da861 100644
--- a/include/media/stagefright/MediaSource.h
+++ b/include/media/stagefright/MediaSource.h
@@ -20,6 +20,7 @@
#include <sys/types.h>
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
@@ -29,7 +30,7 @@
class MediaBuffer;
class MetaData;
-struct MediaSource : public virtual RefBase {
+struct MediaSource : public BnMediaSource {
MediaSource();
// To be called before any other methods on this object, except
@@ -47,8 +48,6 @@
// Returns the format of the data output by this media source.
virtual sp<MetaData> getFormat() = 0;
- struct ReadOptions;
-
// Returns a new buffer of data. Call blocks until a
// buffer is available, an error is encountered of the end of the stream
// is reached.
@@ -59,45 +58,6 @@
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options = NULL) = 0;
- // Options that modify read() behaviour. The default is to
- // a) not request a seek
- // b) not be late, i.e. lateness_us = 0
- struct ReadOptions {
- enum SeekMode {
- SEEK_PREVIOUS_SYNC,
- SEEK_NEXT_SYNC,
- SEEK_CLOSEST_SYNC,
- SEEK_CLOSEST,
- };
-
- ReadOptions();
-
- // Reset everything back to defaults.
- void reset();
-
- void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
- void clearSeekTo();
- bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
-
- void setLateBy(int64_t lateness_us);
- int64_t getLateBy() const;
-
- void setNonBlocking();
- void clearNonBlocking();
- bool getNonBlocking() const;
-
- private:
- enum Options {
- kSeekTo_Option = 1,
- };
-
- uint32_t mOptions;
- int64_t mSeekTimeUs;
- SeekMode mSeekMode;
- int64_t mLatenessUs;
- bool mNonBlocking;
- };
-
// Causes this source to suspend pulling data from its upstream source
// until a subsequent read-with-seek. Currently only supported by
// OMXCodec.
diff --git a/include/media/stagefright/MediaWriter.h b/include/media/stagefright/MediaWriter.h
index 8e02506..b6476c9 100644
--- a/include/media/stagefright/MediaWriter.h
+++ b/include/media/stagefright/MediaWriter.h
@@ -20,10 +20,10 @@
#include <utils/RefBase.h>
#include <media/IMediaRecorderClient.h>
+#include <media/IMediaSource.h>
namespace android {
-struct MediaSource;
class MetaData;
struct MediaWriter : public RefBase {
@@ -32,7 +32,7 @@
mMaxFileDurationLimitUs(0) {
}
- virtual status_t addSource(const sp<MediaSource> &source) = 0;
+ virtual status_t addSource(const sp<IMediaSource> &source) = 0;
virtual bool reachedEOS() = 0;
virtual status_t start(MetaData *params = NULL) = 0;
virtual status_t stop() = 0;
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 8d4e15a..59686ed 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -22,6 +22,7 @@
#include <stdint.h>
+#include <binder/Parcel.h>
#include <utils/RefBase.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
@@ -239,6 +240,10 @@
void dumpToLog() const;
+ status_t writeToParcel(Parcel &parcel);
+ status_t updateFromParcel(const Parcel &parcel);
+ static sp<MetaData> createFromParcel(const Parcel &parcel);
+
protected:
virtual ~MetaData();
diff --git a/include/media/stagefright/NuMediaExtractor.h b/include/media/stagefright/NuMediaExtractor.h
index fd74452..1ba9545 100644
--- a/include/media/stagefright/NuMediaExtractor.h
+++ b/include/media/stagefright/NuMediaExtractor.h
@@ -19,6 +19,7 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/MediaSource.h>
+#include <media/IMediaExtractor.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@@ -84,7 +85,7 @@
};
struct TrackInfo {
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
size_t mTrackIndex;
status_t mFinalResult;
MediaBuffer *mSample;
@@ -97,7 +98,7 @@
sp<DataSource> mDataSource;
- sp<MediaExtractor> mImpl;
+ sp<IMediaExtractor> mImpl;
bool mIsWidevineExtractor;
Vector<TrackInfo> mSelectedTracks;
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 7fabcb3..03ca88b 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -34,7 +34,7 @@
struct CodecProfileLevel;
class SkipCutBuffer;
-struct OMXCodec : public MediaSource,
+struct OMXCodec : public BnMediaSource,
public MediaBufferObserver {
enum CreationFlags {
kPreferSoftwareCodecs = 1,
@@ -61,10 +61,10 @@
// Secure decoding mode
kUseSecureInputBuffers = 256,
};
- static sp<MediaSource> Create(
+ static sp<IMediaSource> Create(
const sp<IOMX> &omx,
const sp<MetaData> &meta, bool createEncoder,
- const sp<MediaSource> &source,
+ const sp<IMediaSource> &source,
const char *matchComponentName = NULL,
uint32_t flags = 0,
const sp<ANativeWindow> &nativeWindow = NULL);
@@ -189,7 +189,7 @@
char *mMIME;
char *mComponentName;
sp<MetaData> mOutputFormat;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
Vector<CodecSpecificData *> mCodecSpecificData;
size_t mCodecSpecificDataIndex;
@@ -234,7 +234,7 @@
OMXCodec(const sp<IOMX> &omx, IOMX::node_id node,
uint32_t quirks, uint32_t flags,
bool isEncoder, const char *mime, const char *componentName,
- const sp<MediaSource> &source,
+ const sp<IMediaSource> &source,
const sp<ANativeWindow> &nativeWindow);
void addCodecSpecificData(const void *data, size_t size);
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 5e9d7d4..17631a0 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -85,6 +85,8 @@
void readFromAMessage(
const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */);
+AString nameForFd(int fd);
+
} // namespace android
#endif // UTILS_H_
diff --git a/include/media/stagefright/timedtext/TimedTextDriver.h b/include/media/stagefright/timedtext/TimedTextDriver.h
index 6f7c693..6e699a6 100644
--- a/include/media/stagefright/timedtext/TimedTextDriver.h
+++ b/include/media/stagefright/timedtext/TimedTextDriver.h
@@ -17,6 +17,7 @@
#ifndef TIMED_TEXT_DRIVER_H_
#define TIMED_TEXT_DRIVER_H_
+#include <media/IMediaSource.h>
#include <media/stagefright/foundation/ABase.h> // for DISALLOW_* macro
#include <utils/Errors.h> // for status_t
#include <utils/RefBase.h>
@@ -27,7 +28,6 @@
struct ALooper;
struct IMediaHTTPService;
class MediaPlayerBase;
-class MediaSource;
class Parcel;
class TimedTextPlayer;
class TimedTextSource;
@@ -49,7 +49,7 @@
status_t seekToAsync(int64_t timeUs);
status_t addInBandTextSource(
- size_t trackIndex, const sp<MediaSource>& source);
+ size_t trackIndex, const sp<IMediaSource>& source);
status_t addOutOfBandTextSource(
size_t trackIndex, const char *uri, const char *mimeType);
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h
index 4f6a1ef..034cb35 100644
--- a/include/ndk/NdkMediaCodec.h
+++ b/include/ndk/NdkMediaCodec.h
@@ -170,6 +170,11 @@
AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1
} cryptoinfo_mode_t;
+typedef struct {
+ int32_t encryptBlocks;
+ int32_t skipBlocks;
+} cryptoinfo_pattern_t;
+
/**
* Create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom
* crypto info, rather than one obtained from AMediaExtractor.
@@ -199,6 +204,13 @@
media_status_t AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*);
/**
+ * Set the crypto pattern on an AMediaCryptoInfo object
+ */
+void AMediaCodecCryptoInfo_setPattern(
+ AMediaCodecCryptoInfo *info,
+ cryptoinfo_pattern_t *pattern);
+
+/**
* The number of subsamples that make up the buffer's contents.
*/
size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*);
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h
index 1e5064f..e458f3c 100644
--- a/include/private/media/AudioTrackShared.h
+++ b/include/private/media/AudioTrackShared.h
@@ -26,6 +26,7 @@
#include <utils/RefBase.h>
#include <audio_utils/roundup.h>
#include <media/AudioResamplerPublic.h>
+#include <media/Modulo.h>
#include <media/SingleStateQueue.h>
namespace android {
@@ -280,11 +281,11 @@
// Call to force an obtainBuffer() to return quickly with -EINTR
void interrupt();
- size_t getPosition() {
+ Modulo<uint32_t> getPosition() {
return mEpoch + mCblk->mServer;
}
- void setEpoch(size_t epoch) {
+ void setEpoch(const Modulo<uint32_t> &epoch) {
mEpoch = epoch;
}
@@ -300,14 +301,12 @@
// in order for the client to be aligned at start of buffer
virtual size_t getMisalignment();
- size_t getEpoch() const {
+ Modulo<uint32_t> getEpoch() const {
return mEpoch;
}
- size_t getFramesFilled();
-
private:
- size_t mEpoch;
+ Modulo<uint32_t> mEpoch;
};
// ----------------------------------------------------------------------------
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
new file mode 100644
index 0000000..324ebbb
--- /dev/null
+++ b/media/audioserver/Android.mk
@@ -0,0 +1,35 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ main_audioserver.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libaudioflinger \
+ libaudiopolicyservice \
+ libbinder \
+ liblog \
+ libmedia \
+ libradioservice \
+ libsoundtriggerservice \
+ libutils \
+
+LOCAL_C_INCLUDES := \
+ frameworks/av/services/audioflinger \
+ frameworks/av/services/audiopolicy \
+ frameworks/av/services/audiopolicy/common/managerdefinitions/include \
+ frameworks/av/services/audiopolicy/common/include \
+ frameworks/av/services/audiopolicy/engine/interface \
+ frameworks/av/services/audiopolicy/service \
+ frameworks/av/services/radio \
+ frameworks/av/services/soundtrigger \
+ $(call include-path-for, audio-utils) \
+ external/sonic \
+
+LOCAL_MODULE := audioserver
+LOCAL_32_BIT_ONLY := true
+
+LOCAL_INIT_RC := audioserver.rc
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/audioserver/audioserver.rc b/media/audioserver/audioserver.rc
new file mode 100644
index 0000000..1b39c8d
--- /dev/null
+++ b/media/audioserver/audioserver.rc
@@ -0,0 +1,6 @@
+service audioserver /system/bin/audioserver
+ class main
+ user audioserver
+ # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
+ group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+ ioprio rt 4
diff --git a/media/audioserver/main_audioserver.cpp b/media/audioserver/main_audioserver.cpp
new file mode 100644
index 0000000..a7123aa
--- /dev/null
+++ b/media/audioserver/main_audioserver.cpp
@@ -0,0 +1,48 @@
+/*
+ * 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 "audioserver"
+//#define LOG_NDEBUG 0
+
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+// from LOCAL_C_INCLUDES
+#include "AudioFlinger.h"
+#include "AudioPolicyService.h"
+#include "RadioService.h"
+#include "SoundTriggerHwService.h"
+
+using namespace android;
+
+int main(int argc __unused, char **argv __unused)
+{
+ signal(SIGPIPE, SIG_IGN);
+
+ // TODO: add logging b/24511453#3
+
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm(defaultServiceManager());
+ ALOGI("ServiceManager: %p", sm.get());
+ AudioFlinger::instantiate();
+ AudioPolicyService::instantiate();
+ RadioService::instantiate();
+ SoundTriggerHwService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 14a1a74..a1892e4 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -722,17 +722,20 @@
if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_WRITE){
pOutTmp = pOut;
- }else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
+ } else if (pContext->config.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE){
if (pContext->pBundledContext->frameCount != frameCount) {
if (pContext->pBundledContext->workBuffer != NULL) {
free(pContext->pBundledContext->workBuffer);
}
pContext->pBundledContext->workBuffer =
- (LVM_INT16 *)malloc(frameCount * sizeof(LVM_INT16) * 2);
+ (LVM_INT16 *)calloc(frameCount, sizeof(LVM_INT16) * 2);
+ if (pContext->pBundledContext->workBuffer == NULL) {
+ return -ENOMEM;
+ }
pContext->pBundledContext->frameCount = frameCount;
}
pOutTmp = pContext->pBundledContext->workBuffer;
- }else{
+ } else {
ALOGV("LVM_ERROR : LvmBundle_process invalid access mode");
return -EINVAL;
}
@@ -2872,7 +2875,7 @@
EffectContext * pContext = (EffectContext *) self;
LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */
int status = 0;
- int lvmStatus = 0;
+ int processStatus = 0;
LVM_INT16 *in = (LVM_INT16 *)inBuffer->raw;
LVM_INT16 *out = (LVM_INT16 *)outBuffer->raw;
@@ -2960,19 +2963,22 @@
//pContext->pBundledContext->NumberEffectsEnabled,
//pContext->pBundledContext->NumberEffectsCalled, pContext->EffectType);
- if(status == -ENODATA){
+ if (status == -ENODATA){
ALOGV("\tEffect_process() processing last frame");
}
pContext->pBundledContext->NumberEffectsCalled = 0;
/* Process all the available frames, block processing is
handled internalLY by the LVM bundle */
- lvmStatus = android::LvmBundle_process( (LVM_INT16 *)inBuffer->raw,
+ processStatus = android::LvmBundle_process( (LVM_INT16 *)inBuffer->raw,
(LVM_INT16 *)outBuffer->raw,
outBuffer->frameCount,
pContext);
- if(lvmStatus != LVM_SUCCESS){
- ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", lvmStatus);
- return lvmStatus;
+ if (processStatus != 0){
+ ALOGV("\tLVM_ERROR : LvmBundle_process returned error %d", processStatus);
+ if (status == 0) {
+ status = processStatus;
+ }
+ return status;
}
} else {
//ALOGV("\tEffect_process Not Calling process with %d effects enabled, %d called: Effect %d",
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index f3c038b..fe41946 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -1224,9 +1224,17 @@
fr = inBuffer->frameCount;
}
if (session->inBufSize < session->framesIn + fr) {
+ int16_t *buf;
session->inBufSize = session->framesIn + fr;
- session->inBuf = (int16_t *)realloc(session->inBuf,
+ buf = (int16_t *)realloc(session->inBuf,
session->inBufSize * session->inChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesIn = 0;
+ free(session->inBuf);
+ session->inBuf = NULL;
+ return -ENOMEM;
+ }
+ session->inBuf = buf;
}
memcpy(session->inBuf + session->framesIn * session->inChannelCount,
inBuffer->s16,
@@ -1296,9 +1304,17 @@
effect->session->apm->ProcessStream(session->procFrame);
if (session->outBufSize < session->framesOut + session->frameCount) {
+ int16_t *buf;
session->outBufSize = session->framesOut + session->frameCount;
- session->outBuf = (int16_t *)realloc(session->outBuf,
- session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ buf = (int16_t *)realloc(session->outBuf,
+ session->outBufSize * session->outChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesOut = 0;
+ free(session->outBuf);
+ session->outBuf = NULL;
+ return -ENOMEM;
+ }
+ session->outBuf = buf;
}
if (session->outResampler != NULL) {
@@ -1754,9 +1770,17 @@
fr = inBuffer->frameCount;
}
if (session->revBufSize < session->framesRev + fr) {
+ int16_t *buf;
session->revBufSize = session->framesRev + fr;
- session->revBuf = (int16_t *)realloc(session->revBuf,
- session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ buf = (int16_t *)realloc(session->revBuf,
+ session->revBufSize * session->inChannelCount * sizeof(int16_t));
+ if (buf == NULL) {
+ session->framesRev = 0;
+ free(session->revBuf);
+ session->revBuf = NULL;
+ return -ENOMEM;
+ }
+ session->revBuf = buf;
}
memcpy(session->revBuf + session->framesRev * session->inChannelCount,
inBuffer->s16,
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index be88aa0..285c33e 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -33,11 +33,14 @@
IMediaHTTPConnection.cpp \
IMediaHTTPService.cpp \
IMediaLogService.cpp \
+ IMediaExtractor.cpp \
+ IMediaExtractorService.cpp \
IMediaPlayerService.cpp \
IMediaPlayerClient.cpp \
IMediaRecorderClient.cpp \
IMediaPlayer.cpp \
IMediaRecorder.cpp \
+ IMediaSource.cpp \
IRemoteDisplay.cpp \
IRemoteDisplayClient.cpp \
IResourceManagerClient.cpp \
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 011b31f..1c0d904 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -308,6 +308,10 @@
mNewPosition = mProxy->getPosition() + mUpdatePeriod;
int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
+ // we reactivate markers (mMarkerPosition != 0) as the position is reset to 0.
+ // This is legacy behavior. This is not done in stop() to avoid a race condition
+ // where the last marker event is issued twice.
+ mMarkerReached = false;
mActive = true;
status_t status = NO_ERROR;
@@ -348,9 +352,10 @@
mActive = false;
mProxy->interrupt();
mAudioRecord->stop();
- // the record head position will reset to 0, so if a marker is set, we need
- // to activate it again
- mMarkerReached = false;
+
+ // Note: legacy handling - stop does not clear record marker and
+ // periodic update position; we update those on start().
+
sp<AudioRecordThread> t = mAudioRecordThread;
if (t != 0) {
t->pause();
@@ -391,7 +396,7 @@
}
AutoMutex lock(mLock);
- *marker = mMarkerPosition;
+ mMarkerPosition.getValue(marker);
return NO_ERROR;
}
@@ -433,7 +438,7 @@
}
AutoMutex lock(mLock);
- *position = mProxy->getPosition();
+ mProxy->getPosition().getValue(position);
return NO_ERROR;
}
@@ -475,7 +480,7 @@
// -------------------------------------------------------------------------
// must be called with mLock held
-status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName)
+status_t AudioRecord::openRecord_l(const Modulo<uint32_t> &epoch, const String16& opPackageName)
{
const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
if (audioFlinger == 0) {
@@ -885,23 +890,23 @@
}
// Get current position of server
- size_t position = mProxy->getPosition();
+ Modulo<uint32_t> position(mProxy->getPosition());
// Manage marker callback
bool markerReached = false;
- size_t markerPosition = mMarkerPosition;
+ Modulo<uint32_t> markerPosition(mMarkerPosition);
// FIXME fails for wraparound, need 64 bits
- if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
+ if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
mMarkerReached = markerReached = true;
}
// Determine the number of new position callback(s) that will be needed, while locked
size_t newPosCount = 0;
- size_t newPosition = mNewPosition;
+ Modulo<uint32_t> newPosition(mNewPosition);
uint32_t updatePeriod = mUpdatePeriod;
// FIXME fails for wraparound, need 64 bits
if (updatePeriod > 0 && position >= newPosition) {
- newPosCount = ((position - newPosition) / updatePeriod) + 1;
+ newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
mNewPosition += updatePeriod * newPosCount;
}
@@ -928,7 +933,7 @@
mCbf(EVENT_MARKER, mUserData, &markerPosition);
}
while (newPosCount > 0) {
- size_t temp = newPosition;
+ size_t temp = newPosition.value(); // FIXME size_t != uint32_t
mCbf(EVENT_NEW_POS, mUserData, &temp);
newPosition += updatePeriod;
newPosCount--;
@@ -946,10 +951,10 @@
// Compute the estimated time until the next timed event (position, markers)
uint32_t minFrames = ~0;
if (!markerReached && position < markerPosition) {
- minFrames = markerPosition - position;
+ minFrames = (markerPosition - position).value();
}
if (updatePeriod > 0) {
- uint32_t remaining = newPosition - position;
+ uint32_t remaining = (newPosition - position).value();
if (remaining < minFrames) {
minFrames = remaining;
}
@@ -1082,7 +1087,7 @@
// if the new IAudioRecord is created, openRecord_l() will modify the
// following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory.
// It will also delete the strong references on previous IAudioRecord and IMemory
- size_t position = mProxy->getPosition();
+ Modulo<uint32_t> position(mProxy->getPosition());
mNewPosition = position + mUpdatePeriod;
status_t result = openRecord_l(position, mOpPackageName);
if (result == NO_ERROR) {
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 9d645f0..1ea2003 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -37,6 +37,7 @@
sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient;
audio_error_callback AudioSystem::gAudioErrorCallback = NULL;
dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL;
+record_config_callback AudioSystem::gRecordConfigCallback = NULL;
// establish binder interface to AudioFlinger service
@@ -652,6 +653,12 @@
gDynPolicyCallback = cb;
}
+/*static*/ void AudioSystem::setRecordConfigCallback(record_config_callback cb)
+{
+ Mutex::Autolock _l(gLock);
+ gRecordConfigCallback = cb;
+}
+
// client singleton for AudioPolicyService binder interface
// protected by gLockAPS
sp<IAudioPolicyService> AudioSystem::gAudioPolicyService;
@@ -1159,6 +1166,20 @@
return aps->stopAudioSource(handle);
}
+status_t AudioSystem::setMasterMono(bool mono)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->setMasterMono(mono);
+}
+
+status_t AudioSystem::getMasterMono(bool *mono)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+ return aps->getMasterMono(mono);
+}
+
// ---------------------------------------------------------------------------
int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
@@ -1223,6 +1244,19 @@
}
}
+void AudioSystem::AudioPolicyServiceClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source) {
+ record_config_callback cb = NULL;
+ {
+ Mutex::Autolock _l(AudioSystem::gLock);
+ cb = gRecordConfigCallback;
+ }
+
+ if (cb != NULL) {
+ cb(event, session, source);
+ }
+}
+
void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused)
{
{
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index 82b6736..5e14940 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -920,7 +920,7 @@
}
AutoMutex lock(mLock);
- *marker = mMarkerPosition;
+ mMarkerPosition.getValue(marker);
return NO_ERROR;
}
@@ -1018,7 +1018,7 @@
// IAudioTrack::stop() isn't synchronous; we don't know when presentation completes
*position = (mState == STATE_STOPPED || mState == STATE_FLUSHED) ?
- 0 : updateAndGetPosition_l();
+ 0 : updateAndGetPosition_l().value();
}
return NO_ERROR;
}
@@ -1774,23 +1774,23 @@
}
// Get current position of server
- size_t position = updateAndGetPosition_l();
+ Modulo<uint32_t> position(updateAndGetPosition_l());
// Manage marker callback
bool markerReached = false;
- size_t markerPosition = mMarkerPosition;
- // FIXME fails for wraparound, need 64 bits
- if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
+ Modulo<uint32_t> markerPosition(mMarkerPosition);
+ // uses 32 bit wraparound for comparison with position.
+ if (!mMarkerReached && markerPosition.value() > 0 && position >= markerPosition) {
mMarkerReached = markerReached = true;
}
// Determine number of new position callback(s) that will be needed, while locked
size_t newPosCount = 0;
- size_t newPosition = mNewPosition;
- size_t updatePeriod = mUpdatePeriod;
+ Modulo<uint32_t> newPosition(mNewPosition);
+ uint32_t updatePeriod = mUpdatePeriod;
// FIXME fails for wraparound, need 64 bits
if (updatePeriod > 0 && position >= newPosition) {
- newPosCount = ((position - newPosition) / updatePeriod) + 1;
+ newPosCount = ((position - newPosition).value() / updatePeriod) + 1;
mNewPosition += updatePeriod * newPosCount;
}
@@ -1891,7 +1891,7 @@
mCbf(EVENT_MARKER, mUserData, &markerPosition);
}
while (newPosCount > 0) {
- size_t temp = newPosition;
+ size_t temp = newPosition.value(); // FIXME size_t != uint32_t
mCbf(EVENT_NEW_POS, mUserData, &temp);
newPosition += updatePeriod;
newPosCount--;
@@ -1915,14 +1915,14 @@
// FIXME only for non-compressed audio
uint32_t minFrames = ~0;
if (!markerReached && position < markerPosition) {
- minFrames = markerPosition - position;
+ minFrames = (markerPosition - position).value();
}
if (loopPeriod > 0 && loopPeriod < minFrames) {
// loopPeriod is already adjusted for actual position.
minFrames = loopPeriod;
}
if (updatePeriod > 0) {
- minFrames = min(minFrames, uint32_t(newPosition - position));
+ minFrames = min(minFrames, (newPosition - position).value());
}
// If > 0, poll periodically to recover from a stuck server. A good value is 2.
@@ -2157,11 +2157,11 @@
return result;
}
-uint32_t AudioTrack::updateAndGetPosition_l()
+Modulo<uint32_t> AudioTrack::updateAndGetPosition_l()
{
// This is the sole place to read server consumed frames
- uint32_t newServer = mProxy->getPosition();
- uint32_t delta = newServer > mServer ? newServer - mServer : 0;
+ Modulo<uint32_t> newServer(mProxy->getPosition());
+ const int32_t delta = (newServer - mServer).signedValue();
// TODO There is controversy about whether there can be "negative jitter" in server position.
// This should be investigated further, and if possible, it should be addressed.
// A more definite failure mode is infrequent polling by client.
@@ -2170,12 +2170,14 @@
// That should ensure delta never goes negative for infrequent polling
// unless the server has more than 2^31 frames in its buffer,
// in which case the use of uint32_t for these counters has bigger issues.
- if (newServer < mServer) {
- ALOGE("detected illegal retrograde motion by the server: mServer advanced by %d",
- (int32_t) newServer - mServer);
- }
+ ALOGE_IF(delta < 0,
+ "detected illegal retrograde motion by the server: mServer advanced by %d",
+ delta);
mServer = newServer;
- return mPosition += delta;
+ if (delta > 0) { // avoid retrograde
+ mPosition += delta;
+ }
+ return mPosition;
}
bool AudioTrack::isSampleRateSpeedAllowed_l(uint32_t sampleRate, float speed) const
@@ -2197,7 +2199,6 @@
return mAudioTrack->setParameters(keyValuePairs);
}
-__attribute__((no_sanitize("integer")))
status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp)
{
AutoMutex lock(mLock);
@@ -2310,15 +2311,19 @@
// If this delta between these is greater than the client position, it means that
// actually presented is still stuck at the starting line (figuratively speaking),
// waiting for the first frame to go by. So we can't report a valid timestamp yet.
- if ((uint32_t) (mServer - timestamp.mPosition) > mPosition) {
+ // Note: We explicitly use non-Modulo comparison here - potential wrap issue when
+ // mPosition exceeds 32 bits.
+ // TODO Remove when timestamp is updated to contain pipeline status info.
+ const int32_t pipelineDepthInFrames = (mServer - timestamp.mPosition).signedValue();
+ if (pipelineDepthInFrames > 0 /* should be true, but we check anyways */
+ && (uint32_t)pipelineDepthInFrames > mPosition.value()) {
return INVALID_OPERATION;
}
// Convert timestamp position from server time base to client time base.
// TODO The following code should work OK now because timestamp.mPosition is 32-bit.
// But if we change it to 64-bit then this could fail.
- // Split this out instead of using += to prevent unsigned overflow
- // checks in the outer sum.
- timestamp.mPosition = timestamp.mPosition + static_cast<int32_t>(mPosition) - mServer;
+ // Use Modulo computation here.
+ timestamp.mPosition = (mPosition - mServer + timestamp.mPosition).value();
// Immediately after a call to getPosition_l(), mPosition and
// mServer both represent the same frame position. mPosition is
// in client's point of view, and mServer is in server's point of
@@ -2332,9 +2337,9 @@
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
if (previousTimestampValid) {
-#define TIME_TO_NANOS(time) ((uint64_t)time.tv_sec * 1000000000 + time.tv_nsec)
- const uint64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
- const uint64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
+#define TIME_TO_NANOS(time) ((int64_t)time.tv_sec * 1000000000 + time.tv_nsec)
+ const int64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime);
+ const int64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime);
#undef TIME_TO_NANOS
if (currentTimeNanos < previousTimeNanos) {
ALOGW("retrograde timestamp time");
@@ -2343,8 +2348,8 @@
// Looking at signed delta will work even when the timestamps
// are wrapping around.
- int32_t deltaPosition = static_cast<int32_t>(timestamp.mPosition
- - mPreviousTimestamp.mPosition);
+ int32_t deltaPosition = (Modulo<uint32_t>(timestamp.mPosition)
+ - mPreviousTimestamp.mPosition).signedValue();
// position can bobble slightly as an artifact; this hides the bobble
static const int32_t MINIMUM_POSITION_DELTA = 8;
if (deltaPosition < 0) {
diff --git a/media/libmedia/AudioTrackShared.cpp b/media/libmedia/AudioTrackShared.cpp
index 9d5d996..9fad500 100644
--- a/media/libmedia/AudioTrackShared.cpp
+++ b/media/libmedia/AudioTrackShared.cpp
@@ -347,27 +347,6 @@
(mFrameCountP2 - 1);
}
-size_t ClientProxy::getFramesFilled() {
- audio_track_cblk_t* cblk = mCblk;
- int32_t front;
- int32_t rear;
-
- if (mIsOut) {
- front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
- rear = cblk->u.mStreaming.mRear;
- } else {
- rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
- front = cblk->u.mStreaming.mFront;
- }
- ssize_t filled = rear - front;
- // pipe should not be overfull
- if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
- ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
- return 0;
- }
- return (size_t)filled;
-}
-
// ---------------------------------------------------------------------------
void AudioTrackClientProxy::flush()
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 76b5924..c95d4c4 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -74,6 +74,8 @@
START_AUDIO_SOURCE,
STOP_AUDIO_SOURCE,
SET_AUDIO_PORT_CALLBACK_ENABLED,
+ SET_MASTER_MONO,
+ GET_MASTER_MONO,
};
#define MAX_ITEMS_PER_LIST 1024
@@ -767,6 +769,37 @@
status = (status_t)reply.readInt32();
return status;
}
+
+ virtual status_t setMasterMono(bool mono)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(static_cast<int32_t>(mono));
+ status_t status = remote()->transact(SET_MASTER_MONO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast<status_t>(reply.readInt32());
+ }
+
+ virtual status_t getMasterMono(bool *mono)
+ {
+ if (mono == nullptr) {
+ return BAD_VALUE;
+ }
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+
+ status_t status = remote()->transact(GET_MASTER_MONO, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = static_cast<status_t>(reply.readInt32());
+ if (status == NO_ERROR) {
+ *mono = static_cast<bool>(reply.readInt32());
+ }
+ return status;
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1311,6 +1344,25 @@
return NO_ERROR;
} break;
+ case SET_MASTER_MONO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool mono = static_cast<bool>(data.readInt32());
+ status_t status = setMasterMono(mono);
+ reply->writeInt32(status);
+ return NO_ERROR;
+ } break;
+
+ case GET_MASTER_MONO: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ bool mono;
+ status_t status = getMasterMono(&mono);
+ reply->writeInt32(status);
+ if (status == NO_ERROR) {
+ reply->writeInt32(static_cast<int32_t>(mono));
+ }
+ return NO_ERROR;
+ } break;
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/IAudioPolicyServiceClient.cpp b/media/libmedia/IAudioPolicyServiceClient.cpp
index 65cc7d6..fe5df28 100644
--- a/media/libmedia/IAudioPolicyServiceClient.cpp
+++ b/media/libmedia/IAudioPolicyServiceClient.cpp
@@ -30,7 +30,8 @@
enum {
PORT_LIST_UPDATE = IBinder::FIRST_CALL_TRANSACTION,
PATCH_LIST_UPDATE,
- MIX_STATE_UPDATE
+ MIX_STATE_UPDATE,
+ RECORDING_CONFIGURATION_UPDATE
};
class BpAudioPolicyServiceClient : public BpInterface<IAudioPolicyServiceClient>
@@ -63,6 +64,16 @@
data.writeInt32(state);
remote()->transact(MIX_STATE_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
}
+
+ void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyServiceClient::getInterfaceDescriptor());
+ data.writeInt32(event);
+ data.writeInt32(session);
+ data.writeInt32(source);
+ remote()->transact(RECORDING_CONFIGURATION_UPDATE, data, &reply, IBinder::FLAG_ONEWAY);
+ }
};
IMPLEMENT_META_INTERFACE(AudioPolicyServiceClient, "android.media.IAudioPolicyServiceClient");
@@ -89,7 +100,15 @@
int32_t state = data.readInt32();
onDynamicPolicyMixStateUpdate(regId, state);
return NO_ERROR;
- }
+ } break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+ CHECK_INTERFACE(IAudioPolicyServiceClient, data, reply);
+ int event = (int) data.readInt32();
+ audio_session_t session = (audio_session_t) data.readInt32();
+ audio_source_t source = (audio_source_t) data.readInt32();
+ onRecordingConfigurationUpdate(event, session, source);
+ return NO_ERROR;
+ } break;
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 22f8af7..79059c6 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -98,7 +98,7 @@
bool secure,
const uint8_t key[16],
const uint8_t iv[16],
- CryptoPlugin::Mode mode,
+ CryptoPlugin::Mode mode, const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
@@ -107,6 +107,8 @@
data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
data.writeInt32(secure);
data.writeInt32(mode);
+ data.writeInt32(pattern.mEncryptBlocks);
+ data.writeInt32(pattern.mSkipBlocks);
static const uint8_t kDummy[16] = { 0 };
@@ -261,7 +263,11 @@
CHECK_INTERFACE(ICrypto, data, reply);
const char *mime = data.readCString();
- reply->writeInt32(requiresSecureDecoderComponent(mime));
+ if (mime == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(requiresSecureDecoderComponent(mime));
+ }
return OK;
}
@@ -272,6 +278,9 @@
bool secure = data.readInt32() != 0;
CryptoPlugin::Mode mode = (CryptoPlugin::Mode)data.readInt32();
+ CryptoPlugin::Pattern pattern;
+ pattern.mEncryptBlocks = data.readInt32();
+ pattern.mSkipBlocks = data.readInt32();
uint8_t key[16];
data.read(key, sizeof(key));
@@ -282,6 +291,10 @@
size_t totalSize = data.readInt32();
sp<IMemory> sharedBuffer =
interface_cast<IMemory>(data.readStrongBinder());
+ if (sharedBuffer == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ return OK;
+ }
int32_t offset = data.readInt32();
int32_t numSubSamples = data.readInt32();
@@ -297,7 +310,7 @@
if (secure) {
secureBufferId = reinterpret_cast<void *>(static_cast<uintptr_t>(data.readInt64()));
} else {
- dstPtr = calloc(1, totalSize);
+ dstPtr = malloc(totalSize);
}
AString errorDetailMsg;
@@ -330,7 +343,7 @@
secure,
key,
iv,
- mode,
+ mode, pattern,
sharedBuffer, offset,
subSamples, numSubSamples,
secure ? secureBufferId : dstPtr,
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index b1ad0c5..5a4591c 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -54,7 +54,6 @@
SIGN_RSA,
VERIFY,
SET_LISTENER,
- UNPROVISION_DEVICE,
GET_SECURE_STOP,
RELEASE_ALL_SECURE_STOPS
};
@@ -277,18 +276,6 @@
return reply.readInt32();
}
- virtual status_t unprovisionDevice() {
- Parcel data, reply;
- data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
-
- status_t status = remote()->transact(UNPROVISION_DEVICE, data, &reply);
- if (status != OK) {
- return status;
- }
-
- return reply.readInt32();
- }
-
virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
@@ -749,14 +736,6 @@
return OK;
}
- case UNPROVISION_DEVICE:
- {
- CHECK_INTERFACE(IDrm, data, reply);
- status_t result = unprovisionDevice();
- reply->writeInt32(result);
- return OK;
- }
-
case GET_SECURE_STOPS:
{
CHECK_INTERFACE(IDrm, data, reply);
diff --git a/media/libmedia/IMediaCodecList.cpp b/media/libmedia/IMediaCodecList.cpp
index e2df104..737f50c 100644
--- a/media/libmedia/IMediaCodecList.cpp
+++ b/media/libmedia/IMediaCodecList.cpp
@@ -157,6 +157,10 @@
{
CHECK_INTERFACE(IMediaCodecList, data, reply);
const char *type = data.readCString();
+ if (type == NULL) {
+ reply->writeInt32(NAME_NOT_FOUND);
+ return NO_ERROR;
+ }
bool isEncoder = static_cast<bool>(data.readInt32());
size_t startIndex = static_cast<size_t>(data.readInt32());
ssize_t index = findCodecByType(type, isEncoder, startIndex);
@@ -172,6 +176,10 @@
{
CHECK_INTERFACE(IMediaCodecList, data, reply);
const char *name = data.readCString();
+ if (name == NULL) {
+ reply->writeInt32(NAME_NOT_FOUND);
+ return NO_ERROR;
+ }
ssize_t index = findCodecByName(name);
if (index > INT32_MAX || index < 0) {
index = NAME_NOT_FOUND;
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
new file mode 100644
index 0000000..76d5648
--- /dev/null
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "BpMediaExtractor"
+#include <utils/Log.h>
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaExtractor.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+ COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
+ GETTRACK,
+ GETTRACKMETADATA,
+ GETMETADATA,
+ FLAGS,
+ SETDRMFLAG,
+ GETDRMFLAG,
+ GETDRMTRACKINFO,
+ SETUID,
+ NAME
+};
+
+class BpMediaExtractor : public BpInterface<IMediaExtractor> {
+public:
+ BpMediaExtractor(const sp<IBinder>& impl)
+ : BpInterface<IMediaExtractor>(impl)
+ {
+ }
+
+ virtual size_t countTracks() {
+ ALOGV("countTracks");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
+ size_t numTracks = 0;
+ if (ret == NO_ERROR) {
+ numTracks = reply.readUint32();
+ }
+ return numTracks;
+ }
+ virtual sp<IMediaSource> getTrack(size_t index) {
+ ALOGV("getTrack(%zu)", index);
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeUint32(index);
+ status_t ret = remote()->transact(GETTRACK, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IMediaSource>(reply.readStrongBinder());
+ }
+ return NULL;
+ }
+
+ virtual sp<MetaData> getTrackMetaData(
+ size_t index, uint32_t flags) {
+ ALOGV("getTrackMetaData(%zu, %u)", index, flags);
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ data.writeUint32(index);
+ data.writeUint32(flags);
+ status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
+ if (ret == NO_ERROR) {
+ return MetaData::createFromParcel(reply);
+ }
+ return NULL;
+ }
+
+ virtual sp<MetaData> getMetaData() {
+ ALOGV("getMetaData");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
+ status_t ret = remote()->transact(GETMETADATA, data, &reply);
+ if (ret == NO_ERROR) {
+ return MetaData::createFromParcel(reply);
+ }
+ return NULL;
+ }
+
+ virtual uint32_t flags() const {
+ ALOGV("flags NOT IMPLEMENTED");
+ return 0;
+ }
+
+ virtual void setDrmFlag(bool flag __unused) {
+ ALOGV("setDrmFlag NOT IMPLEMENTED");
+ }
+ virtual bool getDrmFlag() {
+ ALOGV("getDrmFlag NOT IMPLEMENTED");
+ return false;
+ }
+ virtual char* getDrmTrackInfo(size_t trackID __unused, int *len __unused) {
+ ALOGV("getDrmTrackInfo NOT IMPLEMENTED");
+ return NULL;
+ }
+ virtual void setUID(uid_t uid __unused) {
+ ALOGV("setUID NOT IMPLEMENTED");
+ }
+
+ virtual const char * name() {
+ ALOGV("name NOT IMPLEMENTED");
+ return NULL;
+ }
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaExtractor"
+
+status_t BnMediaExtractor::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case COUNTTRACKS: {
+ ALOGV("countTracks");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ size_t numTracks = countTracks();
+ if (numTracks > INT32_MAX) {
+ numTracks = 0;
+ }
+ reply->writeUint32(uint32_t(numTracks));
+ return NO_ERROR;
+ }
+ case GETTRACK: {
+ ALOGV("getTrack()");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ uint32_t idx;
+ if (data.readUint32(&idx) == NO_ERROR) {
+ return reply->writeStrongBinder(IInterface::asBinder(getTrack((size_t(idx)))));
+ }
+ return UNKNOWN_ERROR;
+ }
+ case GETTRACKMETADATA: {
+ ALOGV("getTrackMetaData");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ uint32_t idx;
+ uint32_t flags;
+ if (data.readUint32(&idx) == NO_ERROR &&
+ data.readUint32(&flags) == NO_ERROR) {
+ sp<MetaData> meta = getTrackMetaData(idx, flags);
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ case GETMETADATA: {
+ ALOGV("getMetaData");
+ CHECK_INTERFACE(IMediaExtractor, data, reply);
+ sp<MetaData> meta = getMetaData();
+ if (meta != NULL) {
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+
+} // namespace android
+
diff --git a/media/libmedia/IMediaExtractorService.cpp b/media/libmedia/IMediaExtractorService.cpp
new file mode 100644
index 0000000..dcbbde2
--- /dev/null
+++ b/media/libmedia/IMediaExtractorService.cpp
@@ -0,0 +1,87 @@
+/*
+**
+** Copyright 2007, 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 "IMediaExtractorService"
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <binder/Parcel.h>
+#include <media/IMediaExtractorService.h>
+
+namespace android {
+
+enum {
+ MAKE_EXTRACTOR = IBinder::FIRST_CALL_TRANSACTION
+};
+
+class BpMediaExtractorService : public BpInterface<IMediaExtractorService>
+{
+public:
+ BpMediaExtractorService(const sp<IBinder>& impl)
+ : BpInterface<IMediaExtractorService>(impl)
+ {
+ }
+
+ virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaExtractorService::getInterfaceDescriptor());
+ data.writeStrongBinder(IInterface::asBinder(source));
+ if (mime != NULL) {
+ data.writeCString(mime);
+ }
+ status_t ret = remote()->transact(MAKE_EXTRACTOR, data, &reply);
+ if (ret == NO_ERROR) {
+ return interface_cast<IMediaExtractor>(reply.readStrongBinder());
+ }
+ return NULL;
+ }
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaExtractorService, "android.media.IMediaExtractorService");
+
+// ----------------------------------------------------------------------
+
+status_t BnMediaExtractorService::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+
+ case MAKE_EXTRACTOR: {
+ CHECK_INTERFACE(IMediaExtractorService, data, reply);
+ sp<IBinder> b;
+ status_t ret = data.readStrongBinder(&b);
+ if (ret != NO_ERROR || b == NULL) {
+ ALOGE("Error reading source from parcel");
+ return ret;
+ }
+ sp<IDataSource> source = interface_cast<IDataSource>(b);
+ const char *mime = data.readCString();
+ sp<IMediaExtractor> ex = makeExtractor(source, mime);
+ reply->writeStrongBinder(IInterface::asBinder(ex));
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+} // namespace android
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index dbf524e..0bee8d3 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -224,6 +224,11 @@
const char* srcUrl = data.readCString();
+ if (httpService == NULL || srcUrl == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ return NO_ERROR;
+ }
+
KeyedVector<String8, String8> headers;
size_t numHeaders = (size_t) data.readInt64();
for (size_t i = 0; i < numHeaders; ++i) {
@@ -250,7 +255,11 @@
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
sp<IDataSource> source =
interface_cast<IDataSource>(data.readStrongBinder());
- reply->writeInt32(setDataSource(source));
+ if (source == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(setDataSource(source));
+ }
return NO_ERROR;
} break;
case GET_FRAME_AT_TIME: {
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 942aec3..c523629 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -444,6 +444,10 @@
}
const char* url = data.readCString();
+ if (httpService == NULL || url == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ return NO_ERROR;
+ }
KeyedVector<String8, String8> headers;
int32_t numHeaders = data.readInt32();
for (int i = 0; i < numHeaders; ++i) {
@@ -467,14 +471,22 @@
CHECK_INTERFACE(IMediaPlayer, data, reply);
sp<IStreamSource> source =
interface_cast<IStreamSource>(data.readStrongBinder());
- reply->writeInt32(setDataSource(source));
+ if (source == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(setDataSource(source));
+ }
return NO_ERROR;
}
case SET_DATA_SOURCE_CALLBACK: {
CHECK_INTERFACE(IMediaPlayer, data, reply);
sp<IDataSource> source =
interface_cast<IDataSource>(data.readStrongBinder());
- reply->writeInt32(setDataSource(source));
+ if (source == NULL) {
+ reply->writeInt32(BAD_VALUE);
+ } else {
+ reply->writeInt32(setDataSource(source));
+ }
return NO_ERROR;
}
case SET_VIDEO_SURFACETEXTURE: {
diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp
index 05f8670..afc94ab 100644
--- a/media/libmedia/IMediaPlayerService.cpp
+++ b/media/libmedia/IMediaPlayerService.cpp
@@ -220,6 +220,10 @@
const String16 opPackageName = data.readString16();
sp<IRemoteDisplayClient> client(
interface_cast<IRemoteDisplayClient>(data.readStrongBinder()));
+ if (client == NULL) {
+ reply->writeStrongBinder(NULL);
+ return NO_ERROR;
+ }
String8 iface(data.readString8());
sp<IRemoteDisplay> display(listenForRemoteDisplay(opPackageName, client, iface));
reply->writeStrongBinder(IInterface::asBinder(display));
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index ee3b584..0eea820 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -54,7 +54,9 @@
SET_PREVIEW_SURFACE,
SET_CAMERA,
SET_LISTENER,
- SET_CLIENT_NAME
+ SET_CLIENT_NAME,
+ PAUSE,
+ RESUME
};
class BpMediaRecorder: public BpInterface<IMediaRecorder>
@@ -276,6 +278,24 @@
return reply.readInt32();
}
+ status_t pause()
+ {
+ ALOGV("pause");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(PAUSE, data, &reply);
+ return reply.readInt32();
+ }
+
+ status_t resume()
+ {
+ ALOGV("resume");
+ Parcel data, reply;
+ data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
+ remote()->transact(RESUME, data, &reply);
+ return reply.readInt32();
+ }
+
status_t close()
{
ALOGV("close");
@@ -340,6 +360,18 @@
reply->writeInt32(start());
return NO_ERROR;
} break;
+ case PAUSE: {
+ ALOGV("PAUSE");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(pause());
+ return NO_ERROR;
+ } break;
+ case RESUME: {
+ ALOGV("RESUME");
+ CHECK_INTERFACE(IMediaRecorder, data, reply);
+ reply->writeInt32(resume());
+ return NO_ERROR;
+ } break;
case PREPARE: {
ALOGV("PREPARE");
CHECK_INTERFACE(IMediaRecorder, data, reply);
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
new file mode 100644
index 0000000..fc9a123
--- /dev/null
+++ b/media/libmedia/IMediaSource.cpp
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "BpMediaSource"
+#include <utils/Log.h>
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <media/IMediaSource.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaSource.h>
+#include <media/stagefright/MetaData.h>
+
+namespace android {
+
+enum {
+ START = IBinder::FIRST_CALL_TRANSACTION,
+ STOP,
+ PAUSE,
+ GETFORMAT,
+ READ,
+ RELEASE_BUFFER
+};
+
+enum {
+ NULL_BUFFER,
+ SHARED_BUFFER,
+ INLINE_BUFFER
+};
+
+class RemoteMediaBufferReleaser : public BBinder {
+public:
+ RemoteMediaBufferReleaser(MediaBuffer *buf) {
+ mBuf = buf;
+ }
+ ~RemoteMediaBufferReleaser() {
+ if (mBuf) {
+ ALOGW("RemoteMediaBufferReleaser dtor called while still holding buffer");
+ mBuf->release();
+ }
+ }
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0) {
+ if (code == RELEASE_BUFFER) {
+ mBuf->release();
+ mBuf = NULL;
+ return OK;
+ } else {
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+ }
+private:
+ MediaBuffer *mBuf;
+};
+
+
+class RemoteMediaBufferWrapper : public MediaBuffer {
+public:
+ RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source);
+protected:
+ virtual ~RemoteMediaBufferWrapper();
+private:
+ sp<IMemory> mMemory;
+ sp<IBinder> mRemoteSource;
+};
+
+RemoteMediaBufferWrapper::RemoteMediaBufferWrapper(sp<IMemory> mem, sp<IBinder> source)
+: MediaBuffer(mem->pointer(), mem->size()) {
+ mMemory = mem;
+ mRemoteSource = source;
+}
+
+RemoteMediaBufferWrapper::~RemoteMediaBufferWrapper() {
+ mMemory.clear();
+ // Explicitly ask the remote side to release the buffer. We could also just clear
+ // mRemoteSource, but that doesn't immediately release the reference on the remote side.
+ Parcel data, reply;
+ mRemoteSource->transact(RELEASE_BUFFER, data, &reply);
+ mRemoteSource.clear();
+}
+
+class BpMediaSource : public BpInterface<IMediaSource> {
+public:
+ BpMediaSource(const sp<IBinder>& impl)
+ : BpInterface<IMediaSource>(impl)
+ {
+ }
+
+ virtual status_t start(MetaData *params) {
+ ALOGV("start");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ if (params) {
+ params->writeToParcel(data);
+ }
+ status_t ret = remote()->transact(START, data, &reply);
+ if (ret == NO_ERROR && params) {
+ ALOGW("ignoring potentially modified MetaData from start");
+ ALOGW("input:");
+ params->dumpToLog();
+ sp<MetaData> meta = MetaData::createFromParcel(reply);
+ ALOGW("output:");
+ meta->dumpToLog();
+ }
+ return ret;
+ }
+
+ virtual status_t stop() {
+ ALOGV("stop");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ return remote()->transact(STOP, data, &reply);
+ }
+
+ virtual sp<MetaData> getFormat() {
+ ALOGV("getFormat");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ status_t ret = remote()->transact(GETFORMAT, data, &reply);
+ if (ret == NO_ERROR) {
+ mMetaData = MetaData::createFromParcel(reply);
+ return mMetaData;
+ }
+ return NULL;
+ }
+
+ virtual status_t read(MediaBuffer **buffer, const ReadOptions *options) {
+ ALOGV("read");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ if (options) {
+ data.writeByteArray(sizeof(*options), (uint8_t*) options);
+ }
+ status_t ret = remote()->transact(READ, data, &reply);
+ if (ret != NO_ERROR) {
+ return ret;
+ }
+ // wrap the returned data in a MediaBuffer
+ ret = reply.readInt32();
+ int32_t buftype = reply.readInt32();
+ if (buftype == SHARED_BUFFER) {
+ sp<IBinder> remote = reply.readStrongBinder();
+ sp<IBinder> binder = reply.readStrongBinder();
+ sp<IMemory> mem = interface_cast<IMemory>(binder);
+ if (mem == NULL) {
+ ALOGE("received NULL IMemory for shared buffer");
+ }
+ size_t offset = reply.readInt32();
+ size_t length = reply.readInt32();
+ MediaBuffer *buf = new RemoteMediaBufferWrapper(mem, remote);
+ buf->set_range(offset, length);
+ buf->meta_data()->updateFromParcel(reply);
+ *buffer = buf;
+ } else if (buftype == NULL_BUFFER) {
+ ALOGV("got status %d and NULL buffer", ret);
+ *buffer = NULL;
+ } else {
+ int32_t len = reply.readInt32();
+ ALOGV("got status %d and len %d", ret, len);
+ *buffer = new MediaBuffer(len);
+ reply.read((*buffer)->data(), len);
+ (*buffer)->meta_data()->updateFromParcel(reply);
+ }
+ return ret;
+ }
+
+ virtual status_t pause() {
+ ALOGV("pause");
+ Parcel data, reply;
+ data.writeInterfaceToken(BpMediaSource::getInterfaceDescriptor());
+ return remote()->transact(PAUSE, data, &reply);
+ }
+
+ virtual status_t setBuffers(const Vector<MediaBuffer *> & buffers __unused) {
+ ALOGV("setBuffers NOT IMPLEMENTED");
+ return ERROR_UNSUPPORTED; // default
+ }
+
+private:
+ // NuPlayer passes pointers-to-metadata around, so we use this to keep the metadata alive
+ // XXX: could we use this for caching, or does metadata change on the fly?
+ sp<MetaData> mMetaData;
+
+};
+
+IMPLEMENT_META_INTERFACE(MediaSource, "android.media.IMediaSource");
+
+#undef LOG_TAG
+#define LOG_TAG "BnMediaSource"
+
+status_t BnMediaSource::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch (code) {
+ case START: {
+ ALOGV("start");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ sp<MetaData> meta;
+ if (data.dataAvail()) {
+ meta = MetaData::createFromParcel(data);
+ }
+ status_t ret = start(meta.get());
+ if (ret == NO_ERROR && meta != NULL) {
+ meta->writeToParcel(*reply);
+ }
+ return ret;
+ }
+ case STOP: {
+ ALOGV("stop");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ return stop();
+ }
+ case PAUSE: {
+ ALOGV("pause");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ return pause();
+ }
+ case GETFORMAT: {
+ ALOGV("getFormat");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ sp<MetaData> meta = getFormat();
+ if (meta != NULL) {
+ meta->writeToParcel(*reply);
+ return NO_ERROR;
+ }
+ return UNKNOWN_ERROR;
+ }
+ case READ: {
+ ALOGV("read");
+ CHECK_INTERFACE(IMediaSource, data, reply);
+ status_t ret;
+ MediaBuffer *buf = NULL;
+ ReadOptions opts;
+ uint32_t len;
+ if (data.readUint32(&len) == NO_ERROR &&
+ len == sizeof(opts) && data.read((void*)&opts, len) == NO_ERROR) {
+ ret = read(&buf, &opts);
+ } else {
+ ret = read(&buf, NULL);
+ }
+
+ reply->writeInt32(ret);
+ if (buf != NULL) {
+ size_t usedSize = buf->range_length();
+ // even if we're using shared memory, we might not want to use it, since for small
+ // sizes it's faster to copy data through the Binder transaction
+ if (buf->mMemory != NULL && usedSize >= 64 * 1024) {
+ ALOGV("buffer is using shared memory: %zu", usedSize);
+ reply->writeInt32(SHARED_BUFFER);
+ RemoteMediaBufferReleaser *wrapper = new RemoteMediaBufferReleaser(buf);
+ reply->writeStrongBinder(wrapper);
+ reply->writeStrongBinder(IInterface::asBinder(buf->mMemory));
+ reply->writeInt32(buf->range_offset());
+ reply->writeInt32(usedSize);
+ buf->meta_data()->writeToParcel(*reply);
+ } else {
+ // buffer is not in shared memory, or is small: copy it
+ if (buf->mMemory != NULL) {
+ ALOGV("%zu shared mem available, but only %zu used", buf->mMemory->size(), buf->range_length());
+ }
+ reply->writeInt32(INLINE_BUFFER);
+ reply->writeByteArray(buf->range_length(), (uint8_t*)buf->data() + buf->range_offset());
+ buf->meta_data()->writeToParcel(*reply);
+ buf->release();
+ }
+ } else {
+ ALOGV("ret %d, buf %p", ret, buf);
+ reply->writeInt32(NULL_BUFFER);
+ }
+ return NO_ERROR;
+ }
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+IMediaSource::ReadOptions::ReadOptions() {
+ reset();
+}
+
+void IMediaSource::ReadOptions::reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mLatenessUs = 0;
+ mNonBlocking = false;
+}
+
+void IMediaSource::ReadOptions::setNonBlocking() {
+ mNonBlocking = true;
+}
+
+void IMediaSource::ReadOptions::clearNonBlocking() {
+ mNonBlocking = false;
+}
+
+bool IMediaSource::ReadOptions::getNonBlocking() const {
+ return mNonBlocking;
+}
+
+void IMediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+ mSeekMode = mode;
+}
+
+void IMediaSource::ReadOptions::clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+ mSeekMode = SEEK_CLOSEST_SYNC;
+}
+
+bool IMediaSource::ReadOptions::getSeekTo(
+ int64_t *time_us, SeekMode *mode) const {
+ *time_us = mSeekTimeUs;
+ *mode = mSeekMode;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+void IMediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
+ mLatenessUs = lateness_us;
+}
+
+int64_t IMediaSource::ReadOptions::getLateBy() const {
+ return mLatenessUs;
+}
+
+
+} // namespace android
+
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index 5423c2a..550b506 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -642,6 +642,12 @@
sp<IOMXObserver> observer =
interface_cast<IOMXObserver>(data.readStrongBinder());
+ if (name == NULL || observer == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
node_id node;
status_t err = allocateNode(name, observer, &node);
@@ -787,6 +793,12 @@
interface_cast<IMemory>(data.readStrongBinder());
OMX_U32 allottedSize = data.readInt32();
+ if (params == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
buffer_id buffer;
status_t err = useBuffer(node, port_index, params, &buffer, allottedSize);
reply->writeInt32(err);
@@ -886,8 +898,13 @@
sp<IGraphicBufferConsumer> bufferConsumer =
interface_cast<IGraphicBufferConsumer>(data.readStrongBinder());
- MetadataBufferType type;
- status_t err = setInputSurface(node, port_index, bufferConsumer, &type);
+ MetadataBufferType type = kMetadataBufferTypeInvalid;
+ status_t err = INVALID_OPERATION;
+ if (bufferConsumer == NULL) {
+ ALOGE("b/26392700");
+ } else {
+ err = setInputSurface(node, port_index, bufferConsumer, &type);
+ }
reply->writeInt32(type);
reply->writeInt32(err);
@@ -995,6 +1012,12 @@
interface_cast<IMemory>(data.readStrongBinder());
OMX_U32 allottedSize = data.readInt32();
+ if (params == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
buffer_id buffer;
status_t err = allocateBufferWithBackup(
node, port_index, params, &buffer, allottedSize);
@@ -1058,6 +1081,12 @@
node_id node = (node_id)data.readInt32();
const char *parameter_name = data.readCString();
+ if (parameter_name == NULL) {
+ ALOGE("b/26392700");
+ reply->writeInt32(INVALID_OPERATION);
+ return NO_ERROR;
+ }
+
OMX_INDEXTYPE index;
status_t err = getExtensionIndex(node, parameter_name, &index);
diff --git a/media/libmedia/IResourceManagerService.cpp b/media/libmedia/IResourceManagerService.cpp
index 4598686..6cb4440 100644
--- a/media/libmedia/IResourceManagerService.cpp
+++ b/media/libmedia/IResourceManagerService.cpp
@@ -132,6 +132,9 @@
int64_t clientId = data.readInt64();
sp<IResourceManagerClient> client(
interface_cast<IResourceManagerClient>(data.readStrongBinder()));
+ if (client == NULL) {
+ return NO_ERROR;
+ }
Vector<MediaResource> resources;
readFromParcel(data, &resources);
addResource(pid, clientId, client, resources);
diff --git a/media/libmedia/IStreamSource.cpp b/media/libmedia/IStreamSource.cpp
index 840e453..8c0905c 100644
--- a/media/libmedia/IStreamSource.cpp
+++ b/media/libmedia/IStreamSource.cpp
@@ -111,7 +111,11 @@
sp<IMemory> mem =
interface_cast<IMemory>(data.readStrongBinder());
- buffers.push(mem);
+ if (mem != NULL) {
+ buffers.push(mem);
+ } else if (data.dataAvail() == 0) {
+ break;
+ }
}
setBuffers(buffers);
break;
diff --git a/media/libmedia/MidiIoWrapper.cpp b/media/libmedia/MidiIoWrapper.cpp
index 5197ce2..faae954 100644
--- a/media/libmedia/MidiIoWrapper.cpp
+++ b/media/libmedia/MidiIoWrapper.cpp
@@ -42,7 +42,7 @@
MidiIoWrapper::MidiIoWrapper(int fd, off64_t offset, int64_t size) {
ALOGV("MidiIoWrapper(fd=%d)", fd);
- mFd = dup(fd);
+ mFd = fd < 0 ? -1 : dup(fd);
mBase = offset;
mLength = size;
}
@@ -61,7 +61,9 @@
MidiIoWrapper::~MidiIoWrapper() {
ALOGV("~MidiIoWrapper");
- close(mFd);
+ if (mFd >= 0) {
+ close(mFd);
+ }
}
int MidiIoWrapper::readAt(void *buffer, int offset, int size) {
@@ -70,6 +72,10 @@
if (mDataSource != NULL) {
return mDataSource->readAt(offset, buffer, size);
}
+ if (mFd < 0) {
+ errno = EBADF;
+ return -1; // as per failed read.
+ }
lseek(mFd, mBase + offset, SEEK_SET);
if (offset + size > mLength) {
size = mLength - offset;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 502ab2d..337e963 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -181,22 +181,6 @@
return err;
}
-status_t MediaPlayer::setDataSource(const sp<IStreamSource> &source)
-{
- ALOGV("setDataSource");
- status_t err = UNKNOWN_ERROR;
- const sp<IMediaPlayerService>& service(getMediaPlayerService());
- if (service != 0) {
- sp<IMediaPlayer> player(service->create(this, mAudioSessionId));
- if ((NO_ERROR != doSetRetransmitEndpoint(player)) ||
- (NO_ERROR != player->setDataSource(source))) {
- player.clear();
- }
- err = attachNewPlayer(player);
- }
- return err;
-}
-
status_t MediaPlayer::setDataSource(const sp<IDataSource> &source)
{
ALOGV("setDataSource(IDataSource)");
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 8bbd8f1..bfdf41d 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -561,6 +561,50 @@
return ret;
}
+status_t MediaRecorder::pause()
+{
+ ALOGV("pause");
+ if (mMediaRecorder == NULL) {
+ ALOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+ ALOGE("stop called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->pause();
+ if (OK != ret) {
+ ALOGE("pause failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
+ return ret;
+}
+
+status_t MediaRecorder::resume()
+{
+ ALOGV("resume");
+ if (mMediaRecorder == NULL) {
+ ALOGE("media recorder is not initialized yet");
+ return INVALID_OPERATION;
+ }
+ if (!(mCurrentState & MEDIA_RECORDER_RECORDING)) {
+ ALOGE("resume called in an invalid state: %d", mCurrentState);
+ return INVALID_OPERATION;
+ }
+
+ status_t ret = mMediaRecorder->resume();
+ if (OK != ret) {
+ ALOGE("resume failed: %d", ret);
+ mCurrentState = MEDIA_RECORDER_ERROR;
+ return ret;
+ }
+
+ return ret;
+}
+
status_t MediaRecorder::close()
{
ALOGV("close");
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 147d35f..b57f6ef 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -239,6 +239,7 @@
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
@@ -256,7 +257,7 @@
const void *srcPtr = static_cast<uint8_t *>(sharedBuffer->pointer()) + offset;
return mPlugin->decrypt(
- secure, key, iv, mode, srcPtr, subSamples, numSubSamples, dstPtr,
+ secure, key, iv, mode, pattern, srcPtr, subSamples, numSubSamples, dstPtr,
errorDetailMsg);
}
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index 99ea95d..7705f30 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -54,6 +54,7 @@
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
const sp<IMemory> &sharedBuffer, size_t offset,
const CryptoPlugin::SubSample *subSamples, size_t numSubSamples,
void *dstPtr,
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index b9cfe80..321ccbf 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -516,24 +516,6 @@
return mPlugin->provideProvisionResponse(response, certificate, wrappedKey);
}
-status_t Drm::unprovisionDevice() {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
- if (mPlugin == NULL) {
- return -EINVAL;
- }
-
- if (!checkPermission("android.permission.REMOVE_DRM_CERTIFICATES")) {
- return -EPERM;
- }
-
- return mPlugin->unprovisionDevice();
-}
-
status_t Drm::getSecureStops(List<Vector<uint8_t> > &secureStops) {
Mutex::Autolock autoLock(mLock);
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 056723c..d40019b 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -77,8 +77,6 @@
Vector<uint8_t> &certificate,
Vector<uint8_t> &wrappedKey);
- virtual status_t unprovisionDevice();
-
virtual status_t getSecureStops(List<Vector<uint8_t> > &secureStops);
virtual status_t getSecureStop(Vector<uint8_t> const &ssid, Vector<uint8_t> &secureStop);
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 3c50747..dda0a57 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -58,6 +58,7 @@
#include <media/stagefright/MediaCodecList.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/AudioPlayer.h>
+#include <media/stagefright/Utils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooperRoster.h>
#include <mediautils/BatteryNotifier.h>
@@ -285,9 +286,7 @@
// reset battery stats
// if the mediaserver has crashed, battery stats could be left
// in bad state, reset the state upon service start.
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
- notifier.noteResetVideo();
- notifier.noteResetAudio();
+ BatteryNotifier::getInstance().noteResetVideo();
MediaPlayerFactory::registerBuiltinFactories();
}
@@ -730,7 +729,8 @@
status_t MediaPlayerService::Client::setDataSource(int fd, int64_t offset, int64_t length)
{
- ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
struct stat sb;
int ret = fstat(fd, &sb);
if (ret != 0) {
@@ -1246,7 +1246,10 @@
if (client->mAudioOutput != NULL)
client->mAudioOutput->switchToNextOutput();
client->mNextClient->start();
- client->mNextClient->mClient->notify(MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+ if (client->mNextClient->mClient != NULL) {
+ client->mNextClient->mClient->notify(
+ MEDIA_INFO, MEDIA_INFO_STARTED_AS_NEXT, 0, obj);
+ }
}
}
@@ -1450,6 +1453,76 @@
return mTrack->getTimestamp(ts);
}
+// TODO: Remove unnecessary calls to getPlayedOutDurationUs()
+// as it acquires locks and may query the audio driver.
+//
+// Some calls could conceivably retrieve extrapolated data instead of
+// accessing getTimestamp() or getPosition() every time a data buffer with
+// a media time is received.
+//
+// Calculate duration of played samples if played at normal rate (i.e., 1.0).
+int64_t MediaPlayerService::AudioOutput::getPlayedOutDurationUs(int64_t nowUs) const
+{
+ Mutex::Autolock lock(mLock);
+ if (mTrack == 0 || mSampleRateHz == 0) {
+ return 0;
+ }
+
+ uint32_t numFramesPlayed;
+ int64_t numFramesPlayedAt;
+ AudioTimestamp ts;
+ static const int64_t kStaleTimestamp100ms = 100000;
+
+ status_t res = mTrack->getTimestamp(ts);
+ if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
+ numFramesPlayed = ts.mPosition;
+ numFramesPlayedAt = ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
+ const int64_t timestampAge = nowUs - numFramesPlayedAt;
+ if (timestampAge > kStaleTimestamp100ms) {
+ // This is an audio FIXME.
+ // getTimestamp returns a timestamp which may come from audio mixing threads.
+ // After pausing, the MixerThread may go idle, thus the mTime estimate may
+ // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
+ // the max latency should be about 25ms with an average around 12ms (to be verified).
+ // For safety we use 100ms.
+ ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
+ (long long)nowUs, (long long)numFramesPlayedAt);
+ numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
+ }
+ //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+ } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
+ numFramesPlayed = 0;
+ numFramesPlayedAt = nowUs;
+ //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
+ // numFramesPlayed, (long long)numFramesPlayedAt);
+ } else { // case 3: transitory at new track or audio fast tracks.
+ res = mTrack->getPosition(&numFramesPlayed);
+ CHECK_EQ(res, (status_t)OK);
+ numFramesPlayedAt = nowUs;
+ numFramesPlayedAt += 1000LL * mTrack->latency() / 2; /* XXX */
+ //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
+ }
+
+ // CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
+ // TODO: remove the (int32_t) casting below as it may overflow at 12.4 hours.
+ int64_t durationUs = (int64_t)((int32_t)numFramesPlayed * 1000000LL / mSampleRateHz)
+ + nowUs - numFramesPlayedAt;
+ if (durationUs < 0) {
+ // Occurs when numFramesPlayed position is very small and the following:
+ // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
+ // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
+ // (2) In case 3, using getPosition and adding mAudioSink->latency() to
+ // numFramesPlayedAt, by a time amount greater than numFramesPlayed.
+ //
+ // Both of these are transitory conditions.
+ ALOGV("getPlayedOutDurationUs: negative duration %lld set to zero", (long long)durationUs);
+ durationUs = 0;
+ }
+ ALOGV("getPlayedOutDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
+ (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
+ return durationUs;
+}
+
status_t MediaPlayerService::AudioOutput::getFramesWritten(uint32_t *frameswritten) const
{
Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 60d4617..bd98ef1 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -88,6 +88,7 @@
virtual float msecsPerFrame() const;
virtual status_t getPosition(uint32_t *position) const;
virtual status_t getTimestamp(AudioTimestamp &ts) const;
+ virtual int64_t getPlayedOutDurationUs(int64_t nowUs) const;
virtual status_t getFramesWritten(uint32_t *frameswritten) const;
virtual int getSessionId() const;
virtual uint32_t getSampleRate() const;
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index 08c7899..3b4e148 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -250,6 +250,29 @@
return mRecorder->stop();
}
+status_t MediaRecorderClient::pause()
+{
+ ALOGV("pause");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->pause();
+
+}
+
+status_t MediaRecorderClient::resume()
+{
+ ALOGV("resume");
+ Mutex::Autolock lock(mLock);
+ if (mRecorder == NULL) {
+ ALOGE("recorder is not initialized");
+ return NO_INIT;
+ }
+ return mRecorder->resume();
+}
+
status_t MediaRecorderClient::init()
{
ALOGV("init");
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index 05130d4..c0d9c4c 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -51,6 +51,8 @@
virtual status_t start();
virtual status_t stop();
virtual status_t reset();
+ virtual status_t pause();
+ virtual status_t resume();
virtual status_t init();
virtual status_t close();
virtual status_t release();
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index b45fd4f..b5e5225 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -35,6 +35,7 @@
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/MediaPlayerInterface.h>
#include <media/stagefright/DataSource.h>
+#include <media/stagefright/Utils.h>
#include <private/media/VideoFrame.h>
#include "MetadataRetrieverClient.h"
#include "StagefrightMetadataRetriever.h"
@@ -133,7 +134,8 @@
status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t length)
{
- ALOGV("setDataSource fd=%d, offset=%lld, length=%lld", fd, offset, length);
+ ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
Mutex::Autolock lock(mLock);
struct stat sb;
int ret = fstat(fd, &sb);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index 36fe800..73d07a0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -907,7 +907,7 @@
return status;
}
-sp<MediaSource> StagefrightRecorder::createAudioSource() {
+sp<MediaCodecSource> StagefrightRecorder::createAudioSource() {
int32_t sourceSampleRate = mSampleRate;
if (mCaptureFpsEnable && mCaptureFps >= mFrameRate) {
@@ -982,7 +982,7 @@
}
format->setInt32("priority", 0 /* realtime */);
- sp<MediaSource> audioEncoder =
+ sp<MediaCodecSource> audioEncoder =
MediaCodecSource::Create(mLooper, format, audioSource);
mAudioSourceNode = audioSource;
@@ -1041,13 +1041,14 @@
return status;
}
- sp<MediaSource> audioEncoder = createAudioSource();
+ sp<MediaCodecSource> audioEncoder = createAudioSource();
if (audioEncoder == NULL) {
return UNKNOWN_ERROR;
}
CHECK(mWriter != 0);
mWriter->addSource(audioEncoder);
+ mAudioEncoderSource = audioEncoder;
if (mMaxFileDurationUs != 0) {
mWriter->setMaxFileDuration(mMaxFileDurationUs);
@@ -1075,10 +1076,11 @@
return BAD_VALUE;
}
- sp<MediaSource> source;
+ sp<MediaCodecSource> source;
if (mAudioSource != AUDIO_SOURCE_CNT) {
source = createAudioSource();
+ mAudioEncoderSource = source;
} else {
setDefaultVideoEncoderIfNecessary();
@@ -1092,6 +1094,7 @@
if (err != OK) {
return err;
}
+ mVideoEncoderSource = source;
}
mWriter = new ARTPWriter(mOutputFd);
@@ -1132,7 +1135,7 @@
return err;
}
- sp<MediaSource> encoder;
+ sp<MediaCodecSource> encoder;
err = setupVideoEncoder(mediaSource, &encoder);
if (err != OK) {
@@ -1140,6 +1143,7 @@
}
writer->addSource(encoder);
+ mVideoEncoderSource = encoder;
}
if (mMaxFileDurationUs != 0) {
@@ -1489,7 +1493,7 @@
status_t StagefrightRecorder::setupVideoEncoder(
sp<MediaSource> cameraSource,
- sp<MediaSource> *source) {
+ sp<MediaCodecSource> *source) {
source->clear();
sp<AMessage> format = new AMessage();
@@ -1618,12 +1622,13 @@
return UNKNOWN_ERROR;
}
- sp<MediaSource> audioEncoder = createAudioSource();
+ sp<MediaCodecSource> audioEncoder = createAudioSource();
if (audioEncoder == NULL) {
return UNKNOWN_ERROR;
}
writer->addSource(audioEncoder);
+ mAudioEncoderSource = audioEncoder;
return OK;
}
@@ -1649,13 +1654,14 @@
return err;
}
- sp<MediaSource> encoder;
+ sp<MediaCodecSource> encoder;
err = setupVideoEncoder(mediaSource, &encoder);
if (err != OK) {
return err;
}
writer->addSource(encoder);
+ mVideoEncoderSource = encoder;
mTotalBitRate += mVideoBitRate;
}
@@ -1726,25 +1732,49 @@
status_t StagefrightRecorder::pause() {
ALOGV("pause");
- if (mWriter == NULL) {
- return UNKNOWN_ERROR;
- }
- mWriter->pause();
-
- if (mStarted) {
- mStarted = false;
-
- uint32_t params = 0;
- if (mAudioSource != AUDIO_SOURCE_CNT) {
- params |= IMediaPlayerService::kBatteryDataTrackAudio;
- }
- if (mVideoSource != VIDEO_SOURCE_LIST_END) {
- params |= IMediaPlayerService::kBatteryDataTrackVideo;
- }
-
- addBatteryData(params);
+ if (!mStarted) {
+ return INVALID_OPERATION;
}
+ // Already paused --- no-op.
+ if (mPauseStartTimeUs != 0) {
+ return OK;
+ }
+
+ if (mAudioEncoderSource != NULL) {
+ mAudioEncoderSource->pause();
+ }
+ if (mVideoEncoderSource != NULL) {
+ mVideoEncoderSource->pause();
+ }
+
+ mPauseStartTimeUs = systemTime() / 1000;
+
+ return OK;
+}
+
+status_t StagefrightRecorder::resume() {
+ ALOGV("resume");
+ if (!mStarted) {
+ return INVALID_OPERATION;
+ }
+
+ // Not paused --- no-op.
+ if (mPauseStartTimeUs == 0) {
+ return OK;
+ }
+
+ // 30 ms buffer to avoid timestamp overlap
+ mTotalPausedDurationUs += (systemTime() / 1000) - mPauseStartTimeUs - 30000;
+ if (mAudioEncoderSource != NULL) {
+ mAudioEncoderSource->setInputBufferTimeOffset(-mTotalPausedDurationUs);
+ mAudioEncoderSource->start();
+ }
+ if (mVideoEncoderSource != NULL) {
+ mVideoEncoderSource->setInputBufferTimeOffset(-mTotalPausedDurationUs);
+ mVideoEncoderSource->start();
+ }
+ mPauseStartTimeUs = 0;
return OK;
}
@@ -1765,6 +1795,8 @@
mGraphicBufferProducer.clear();
mPersistentSurface.clear();
+ mAudioEncoderSource.clear();
+ mVideoEncoderSource.clear();
if (mOutputFd >= 0) {
::close(mOutputFd);
@@ -1840,6 +1872,8 @@
mTotalBitRate = 0;
mOutputFd = -1;
+ mPauseStartTimeUs = 0;
+ mTotalPausedDurationUs = 0;
return OK;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index da00bc7..a799e9d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -30,6 +30,7 @@
class ICameraRecordingProxy;
class CameraSource;
class CameraSourceTimeLapse;
+struct MediaCodecSource;
struct MediaSource;
struct MediaWriter;
class MetaData;
@@ -62,6 +63,7 @@
virtual status_t prepare();
virtual status_t start();
virtual status_t pause();
+ virtual status_t resume();
virtual status_t stop();
virtual status_t close();
virtual status_t reset();
@@ -121,6 +123,11 @@
bool mIsMetaDataStoredInVideoBuffers;
MediaProfiles *mEncoderProfiles;
+ int64_t mPauseStartTimeUs;
+ int64_t mTotalPausedDurationUs;
+ sp<MediaCodecSource> mAudioEncoderSource;
+ sp<MediaCodecSource> mVideoEncoderSource;
+
bool mStarted;
// Needed when GLFrames are encoded.
// An <IGraphicBufferProducer> pointer
@@ -139,7 +146,7 @@
status_t setupRawAudioRecording();
status_t setupRTPRecording();
status_t setupMPEG2TSRecording();
- sp<MediaSource> createAudioSource();
+ sp<MediaCodecSource> createAudioSource();
status_t checkVideoEncoderCapabilities();
status_t checkAudioEncoderCapabilities();
// Generic MediaSource set-up. Returns the appropriate
@@ -148,7 +155,7 @@
status_t setupMediaSource(sp<MediaSource> *mediaSource);
status_t setupCameraSource(sp<CameraSource> *cameraSource);
status_t setupAudioEncoder(const sp<MediaWriter>& writer);
- status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
+ status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaCodecSource> *source);
// Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 45da218..9a0db30 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -135,7 +135,7 @@
}
status_t NuPlayer::GenericSource::initFromDataSource() {
- sp<MediaExtractor> extractor;
+ sp<IMediaExtractor> extractor;
String8 mimeType;
float confidence;
sp<AMessage> dummy;
@@ -210,9 +210,16 @@
}
for (size_t i = 0; i < numtracks; ++i) {
- sp<MediaSource> track = extractor->getTrack(i);
+ sp<IMediaSource> track = extractor->getTrack(i);
+ if (track == NULL) {
+ continue;
+ }
sp<MetaData> meta = extractor->getTrackMetaData(i);
+ if (meta == NULL) {
+ ALOGE("no metadata for track %zu", i);
+ return UNKNOWN_ERROR;
+ }
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -253,22 +260,25 @@
}
}
- if (track != NULL) {
- mSources.push(track);
- int64_t durationUs;
- if (meta->findInt64(kKeyDuration, &durationUs)) {
- if (durationUs > mDurationUs) {
- mDurationUs = durationUs;
- }
- }
-
- int32_t bitrate;
- if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
- totalBitrate += bitrate;
- } else {
- totalBitrate = -1;
+ mSources.push(track);
+ int64_t durationUs;
+ if (meta->findInt64(kKeyDuration, &durationUs)) {
+ if (durationUs > mDurationUs) {
+ mDurationUs = durationUs;
}
}
+
+ int32_t bitrate;
+ if (totalBitrate >= 0 && meta->findInt32(kKeyBitRate, &bitrate)) {
+ totalBitrate += bitrate;
+ } else {
+ totalBitrate = -1;
+ }
+ }
+
+ if (mSources.size() == 0) {
+ ALOGE("b/23705695");
+ return UNKNOWN_ERROR;
}
mBitrate = totalBitrate;
@@ -318,7 +328,7 @@
status_t NuPlayer::GenericSource::setBuffers(
bool audio, Vector<MediaBuffer *> &buffers) {
- if (mIsSecure && !audio) {
+ if (mIsSecure && !audio && mVideoTrack.mSource != NULL) {
return mVideoTrack.mSource->setBuffers(buffers);
}
return INVALID_OPERATION;
@@ -765,6 +775,11 @@
break;
}
+ case kWhatSendGlobalTimedTextData:
+ {
+ sendGlobalTextData(kWhatTimedTextData, mFetchTimedTextDataGeneration, msg);
+ break;
+ }
case kWhatSendTimedTextData:
{
sendTextData(kWhatTimedTextData, MEDIA_TRACK_TYPE_TIMEDTEXT,
@@ -776,7 +791,7 @@
{
int32_t trackIndex;
CHECK(msg->findInt32("trackIndex", &trackIndex));
- const sp<MediaSource> source = mSources.itemAt(trackIndex);
+ const sp<IMediaSource> source = mSources.itemAt(trackIndex);
Track* track;
const char *mime;
@@ -959,16 +974,47 @@
}
}
+void NuPlayer::GenericSource::sendGlobalTextData(
+ uint32_t what,
+ int32_t curGen,
+ sp<AMessage> msg) {
+ int32_t msgGeneration;
+ CHECK(msg->findInt32("generation", &msgGeneration));
+ if (msgGeneration != curGen) {
+ // stale
+ return;
+ }
+
+ uint32_t textType;
+ const void *data;
+ size_t size = 0;
+ if (mTimedTextTrack.mSource->getFormat()->findData(
+ kKeyTextFormatData, &textType, &data, &size)) {
+ mGlobalTimedText = new ABuffer(size);
+ if (mGlobalTimedText->data()) {
+ memcpy(mGlobalTimedText->data(), data, size);
+ sp<AMessage> globalMeta = mGlobalTimedText->meta();
+ globalMeta->setInt64("timeUs", 0);
+ globalMeta->setString("mime", MEDIA_MIMETYPE_TEXT_3GPP);
+ globalMeta->setInt32("global", 1);
+ sp<AMessage> notify = dupNotify();
+ notify->setInt32("what", what);
+ notify->setBuffer("buffer", mGlobalTimedText);
+ notify->post();
+ }
+ }
+}
+
sp<MetaData> NuPlayer::GenericSource::getFormatMeta(bool audio) {
sp<AMessage> msg = new AMessage(kWhatGetFormat, this);
msg->setInt32("audio", audio);
sp<AMessage> response;
- void *format;
+ sp<RefBase> format;
status_t err = msg->postAndAwaitResponse(&response);
if (err == OK && response != NULL) {
- CHECK(response->findPointer("format", &format));
- return (MetaData *)format;
+ CHECK(response->findObject("format", &format));
+ return static_cast<MetaData*>(format.get());
} else {
return NULL;
}
@@ -980,7 +1026,7 @@
sp<AMessage> response = new AMessage;
sp<MetaData> format = doGetFormatMeta(audio);
- response->setPointer("format", format.get());
+ response->setObject("format", format);
sp<AReplyToken> replyID;
CHECK(msg->senderAwaitsResponse(&replyID));
@@ -988,7 +1034,7 @@
}
sp<MetaData> NuPlayer::GenericSource::doGetFormatMeta(bool audio) const {
- sp<MediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
+ sp<IMediaSource> source = audio ? mAudioTrack.mSource : mVideoTrack.mSource;
if (source == NULL) {
return NULL;
@@ -1085,6 +1131,10 @@
sp<AMessage> format = new AMessage();
sp<MetaData> meta = mSources.itemAt(trackIndex)->getFormat();
+ if (meta == NULL) {
+ ALOGE("no metadata for track %zu", trackIndex);
+ return NULL;
+ }
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1232,7 +1282,7 @@
return OK;
}
- const sp<MediaSource> source = mSources.itemAt(trackIndex);
+ const sp<IMediaSource> source = mSources.itemAt(trackIndex);
sp<MetaData> meta = source->getFormat();
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1271,6 +1321,10 @@
msg->post();
}
+ sp<AMessage> msg2 = new AMessage(kWhatSendGlobalTimedTextData, this);
+ msg2->setInt32("generation", mFetchTimedTextDataGeneration);
+ msg2->post();
+
if (mTimedTextTrack.mSource != NULL
&& !mTimedTextTrack.mPackets->hasBufferAvailable(&eosResult)) {
sp<AMessage> msg = new AMessage(kWhatFetchTimedTextData, this);
@@ -1538,7 +1592,8 @@
queueDiscontinuityIfNeeded(seeking, formatChange, trackType, track);
sp<ABuffer> buffer = mediaBufferToABuffer(
- mbuf, trackType, seekTimeUs, actualTimeUs);
+ mbuf, trackType, seekTimeUs,
+ numBuffers == 0 ? actualTimeUs : NULL);
track->mPackets->queueAccessUnit(buffer);
formatChange = false;
seeking = false;
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.h b/media/libmediaplayerservice/nuplayer/GenericSource.h
index ac980ef..2db5557 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.h
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.h
@@ -90,6 +90,7 @@
kWhatFetchSubtitleData,
kWhatFetchTimedTextData,
kWhatSendSubtitleData,
+ kWhatSendGlobalTimedTextData,
kWhatSendTimedTextData,
kWhatChangeAVSource,
kWhatPollBuffering,
@@ -106,11 +107,11 @@
struct Track {
size_t mIndex;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<AnotherPacketSource> mPackets;
};
- Vector<sp<MediaSource> > mSources;
+ Vector<sp<IMediaSource> > mSources;
Track mAudioTrack;
int64_t mAudioTimeUs;
int64_t mAudioLastDequeueTimeUs;
@@ -151,6 +152,7 @@
bool mBuffering;
bool mPrepareBuffering;
int32_t mPrevBufferPercentage;
+ sp<ABuffer> mGlobalTimedText;
mutable Mutex mReadBufferLock;
mutable Mutex mDisconnectLock;
@@ -187,6 +189,10 @@
uint32_t what, media_track_type type,
int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
+ void sendGlobalTextData(
+ uint32_t what,
+ int32_t curGen, sp<AMessage> msg);
+
void sendTextData(
uint32_t what, media_track_type type,
int32_t curGen, sp<AnotherPacketSource> packets, sp<AMessage> msg);
diff --git a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
index 126625a..3fffdc1a 100644
--- a/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/HTTPLiveSource.cpp
@@ -101,15 +101,20 @@
}
sp<AMessage> NuPlayer::HTTPLiveSource::getFormat(bool audio) {
- if (mLiveSession == NULL) {
- return NULL;
+ sp<AMessage> format;
+ status_t err = -EWOULDBLOCK;
+ if (mLiveSession != NULL) {
+ err = mLiveSession->getStreamFormat(
+ audio ? LiveSession::STREAMTYPE_AUDIO
+ : LiveSession::STREAMTYPE_VIDEO,
+ &format);
}
- sp<AMessage> format;
- status_t err = mLiveSession->getStreamFormat(
- audio ? LiveSession::STREAMTYPE_AUDIO
- : LiveSession::STREAMTYPE_VIDEO,
- &format);
+ if (err == -EWOULDBLOCK) {
+ format = new AMessage();
+ format->setInt32("err", err);
+ return format;
+ }
if (err != OK) {
return NULL;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 36c38a2..ce68bd4 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -422,8 +422,15 @@
void NuPlayer::writeTrackInfo(
Parcel* reply, const sp<AMessage> format) const {
+ if (format == NULL) {
+ ALOGE("NULL format");
+ return;
+ }
int32_t trackType;
- CHECK(format->findInt32("type", &trackType));
+ if (!format->findInt32("type", &trackType)) {
+ ALOGE("no track type");
+ return;
+ }
AString mime;
if (!format->findString("mime", &mime)) {
@@ -436,12 +443,16 @@
} else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
mime = "video/";
} else {
- TRESPASS();
+ ALOGE("unknown track type: %d", trackType);
+ return;
}
}
AString lang;
- CHECK(format->findString("language", &lang));
+ if (!format->findString("language", &lang)) {
+ ALOGE("no language");
+ return;
+ }
reply->writeInt32(2); // write something non-zero
reply->writeInt32(trackType);
@@ -834,16 +845,21 @@
bool mHadAnySourcesBefore =
(mAudioDecoder != NULL) || (mVideoDecoder != NULL);
+ bool rescan = false;
// initialize video before audio because successful initialization of
// video may change deep buffer mode of audio.
if (mSurface != NULL) {
- instantiateDecoder(false, &mVideoDecoder);
+ if (instantiateDecoder(false, &mVideoDecoder) == -EWOULDBLOCK) {
+ rescan = true;
+ }
}
// Don't try to re-open audio sink if there's an existing decoder.
if (mAudioSink != NULL && mAudioDecoder == NULL) {
- instantiateDecoder(true, &mAudioDecoder);
+ if (instantiateDecoder(true, &mAudioDecoder) == -EWOULDBLOCK) {
+ rescan = true;
+ }
}
if (!mHadAnySourcesBefore
@@ -870,8 +886,7 @@
break;
}
- if ((mAudioDecoder == NULL && mAudioSink != NULL)
- || (mVideoDecoder == NULL && mSurface != NULL)) {
+ if (rescan) {
msg->post(100000ll);
mScanSourcesPending = true;
}
@@ -1306,6 +1321,7 @@
}
sp<MetaData> audioMeta = mSource->getFormatMeta(true /* audio */);
+ ALOGV_IF(audioMeta == NULL, "no metadata for audio source"); // video only stream
audio_stream_type_t streamType = AUDIO_STREAM_MUSIC;
if (mAudioSink != NULL) {
streamType = mAudioSink->getAudioStreamType();
@@ -1508,7 +1524,12 @@
sp<AMessage> format = mSource->getFormat(audio);
if (format == NULL) {
- return -EWOULDBLOCK;
+ return UNKNOWN_ERROR;
+ } else {
+ status_t err;
+ if (format->findInt32("err", &err) && err) {
+ return err;
+ }
}
format->setInt32("priority", 0 /* realtime */);
@@ -2302,7 +2323,7 @@
const void *data;
size_t size = 0;
int64_t timeUs;
- int32_t flag = TextDescriptions::LOCAL_DESCRIPTIONS;
+ int32_t flag = TextDescriptions::IN_BAND_TEXT_3GPP;
AString mime;
CHECK(buffer->meta()->findString("mime", &mime));
@@ -2314,7 +2335,12 @@
Parcel parcel;
if (size > 0) {
CHECK(buffer->meta()->findInt64("timeUs", &timeUs));
- flag |= TextDescriptions::IN_BAND_TEXT_3GPP;
+ int32_t global = 0;
+ if (buffer->meta()->findInt32("global", &global) && global) {
+ flag |= TextDescriptions::GLOBAL_DESCRIPTIONS;
+ } else {
+ flag |= TextDescriptions::LOCAL_DESCRIPTIONS;
+ }
TextDescriptions::getParcelOfDescriptions(
(const uint8_t *)data, size, flag, timeUs / 1000, &parcel);
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index f288c36..65e3a6e 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -390,7 +390,7 @@
}
status_t NuPlayerDriver::seekTo(int msec) {
- ALOGD("seekTo(%p) %d ms", this, msec);
+ ALOGD("seekTo(%p) %d ms at state %d", this, msec, mState);
Mutex::Autolock autoLock(mLock);
int64_t seekTimeUs = msec * 1000ll;
@@ -458,7 +458,7 @@
}
status_t NuPlayerDriver::reset() {
- ALOGD("reset(%p)", this);
+ ALOGD("reset(%p) at state %d", this, mState);
Mutex::Autolock autoLock(mLock);
switch (mState) {
@@ -725,7 +725,8 @@
void NuPlayerDriver::notifyListener_l(
int msg, int ext1, int ext2, const Parcel *in) {
- ALOGD("notifyListener_l(%p), (%d, %d, %d)", this, msg, ext1, ext2);
+ ALOGD("notifyListener_l(%p), (%d, %d, %d), loop setting(%d, %d)",
+ this, msg, ext1, ext2, mAutoLoop, mLooping);
switch (msg) {
case MEDIA_PLAYBACK_COMPLETE:
{
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index c6a7805..7535934 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -95,6 +95,7 @@
mVideoQueueGeneration(0),
mAudioDrainGeneration(0),
mVideoDrainGeneration(0),
+ mAudioEOSGeneration(0),
mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
mAudioFirstAnchorTimeMediaUs(-1),
mAnchorTimeMediaUs(-1),
@@ -112,6 +113,7 @@
mVideoRenderingStartGeneration(0),
mAudioRenderingStartGeneration(0),
mRenderingDataDelivered(false),
+ mLastAudioMediaTimeUs(-1),
mAudioOffloadPauseTimeoutGeneration(0),
mAudioTornDown(false),
mCurrentOffloadInfo(AUDIO_INFO_INITIALIZER),
@@ -311,8 +313,33 @@
msg->post();
}
-// Called on any threads.
+// Called on any threads without mLock acquired.
status_t NuPlayer::Renderer::getCurrentPosition(int64_t *mediaUs) {
+ status_t result = mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
+ if (result == OK) {
+ return result;
+ }
+
+ // MediaClock has not started yet. Try to start it if possible.
+ {
+ Mutex::Autolock autoLock(mLock);
+ if (mAudioFirstAnchorTimeMediaUs == -1) {
+ return result;
+ }
+
+ AudioTimestamp ts;
+ status_t res = mAudioSink->getTimestamp(ts);
+ if (res != OK) {
+ return result;
+ }
+
+ // AudioSink has rendered some frames.
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t nowMediaUs = mAudioSink->getPlayedOutDurationUs(nowUs)
+ + mAudioFirstAnchorTimeMediaUs;
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, -1);
+ }
+
return mMediaClock->getMediaTime(ALooper::GetNowUs(), mediaUs);
}
@@ -500,6 +527,19 @@
break;
}
+ case kWhatEOS:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("audioEOSGeneration", &generation));
+ if (generation != mAudioEOSGeneration) {
+ break;
+ }
+ status_t finalResult;
+ CHECK(msg->findInt32("finalResult", &finalResult));
+ notifyEOS(true /* audio */, finalResult);
+ break;
+ }
+
case kWhatConfigPlayback:
{
sp<AReplyToken> replyID;
@@ -755,7 +795,7 @@
if (mAudioFirstAnchorTimeMediaUs >= 0) {
int64_t nowUs = ALooper::GetNowUs();
int64_t nowMediaUs =
- mAudioFirstAnchorTimeMediaUs + getPlayedOutAudioDurationUs(nowUs);
+ mAudioFirstAnchorTimeMediaUs + mAudioSink->getPlayedOutDurationUs(nowUs);
// we don't know how much data we are queueing for offloaded tracks.
mMediaClock->updateAnchor(nowMediaUs, nowUs, INT64_MAX);
}
@@ -864,6 +904,7 @@
postEOSDelayUs = getPendingAudioPlayoutDurationUs(ALooper::GetNowUs());
}
notifyEOS(true /* audio */, entry->mFinalResult, postEOSDelayUs);
+ mLastAudioMediaTimeUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
mAudioQueue.erase(mAudioQueue.begin());
entry = NULL;
@@ -973,7 +1014,7 @@
// Calculate duration of pending samples if played at normal rate (i.e., 1.0).
int64_t NuPlayer::Renderer::getPendingAudioPlayoutDurationUs(int64_t nowUs) {
int64_t writtenAudioDurationUs = getDurationUsIfPlayedAtSampleRate(mNumFramesWritten);
- return writtenAudioDurationUs - getPlayedOutAudioDurationUs(nowUs);
+ return writtenAudioDurationUs - mAudioSink->getPlayedOutDurationUs(nowUs);
}
int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
@@ -994,9 +1035,14 @@
return;
}
setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
- int64_t nowUs = ALooper::GetNowUs();
- int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
- mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+
+ AudioTimestamp ts;
+ status_t res = mAudioSink->getTimestamp(ts);
+ if (res == OK) {
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t nowMediaUs = mediaTimeUs - getPendingAudioPlayoutDurationUs(nowUs);
+ mMediaClock->updateAnchor(nowMediaUs, nowUs, mediaTimeUs);
+ }
mAnchorNumFramesWritten = mNumFramesWritten;
mAnchorTimeMediaUs = mediaTimeUs;
}
@@ -1025,6 +1071,7 @@
return;
}
+ bool needRepostDrainVideoQueue = false;
int64_t delayUs;
int64_t nowUs = ALooper::GetNowUs();
int64_t realTimeUs;
@@ -1045,8 +1092,14 @@
} else if (!mVideoSampleReceived) {
// Always render the first video frame.
realTimeUs = nowUs;
- } else {
+ } else if (mAudioFirstAnchorTimeMediaUs < 0
+ || mMediaClock->getRealTimeFor(mediaTimeUs, &realTimeUs) == OK) {
realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
+ } else if (mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0) {
+ needRepostDrainVideoQueue = true;
+ realTimeUs = nowUs;
+ } else {
+ realTimeUs = nowUs;
}
}
if (!mHasAudio) {
@@ -1059,15 +1112,25 @@
// received after this buffer, repost in 10 msec. Otherwise repost
// in 500 msec.
delayUs = realTimeUs - nowUs;
+ int64_t postDelayUs = -1;
if (delayUs > 500000) {
- int64_t postDelayUs = 500000;
+ postDelayUs = 500000;
if (mHasAudio && (mLastAudioBufferDrained - entry.mBufferOrdinal) <= 0) {
postDelayUs = 10000;
}
+ } else if (needRepostDrainVideoQueue) {
+ // CHECK(mPlaybackRate > 0);
+ // CHECK(mAudioFirstAnchorTimeMediaUs >= 0);
+ // CHECK(mediaTimeUs - mAudioFirstAnchorTimeMediaUs >= 0);
+ postDelayUs = mediaTimeUs - mAudioFirstAnchorTimeMediaUs;
+ postDelayUs /= mPlaybackRate;
+ }
+
+ if (postDelayUs >= 0) {
msg->setWhat(kWhatPostDrainVideoQueue);
msg->post(postDelayUs);
mVideoScheduler->restart();
- ALOGI("possible video time jump of %dms, retrying in %dms",
+ ALOGI("possible video time jump of %dms or uninitialized media clock, retrying in %dms",
(int)(delayUs / 1000), (int)(postDelayUs / 1000));
mDrainVideoQueuePending = true;
return;
@@ -1107,10 +1170,10 @@
int64_t nowUs = ALooper::GetNowUs();
int64_t realTimeUs;
+ int64_t mediaTimeUs = -1;
if (mFlags & FLAG_REAL_TIME) {
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
} else {
- int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
realTimeUs = getRealTimeUs(mediaTimeUs, nowUs);
@@ -1131,6 +1194,14 @@
ALOGV("rendering video at media time %.2f secs",
(mFlags & FLAG_REAL_TIME ? realTimeUs :
mediaUs) / 1E6);
+
+ if (!(mFlags & FLAG_REAL_TIME)
+ && mLastAudioMediaTimeUs != -1
+ && mediaTimeUs > mLastAudioMediaTimeUs) {
+ // If audio ends before video, video continues to drive media clock.
+ // Also smooth out videos >= 10fps.
+ mMediaClock->updateMaxTimeMedia(mediaTimeUs + 100000);
+ }
}
} else {
setVideoLateByUs(0);
@@ -1173,6 +1244,13 @@
}
void NuPlayer::Renderer::notifyEOS(bool audio, status_t finalResult, int64_t delayUs) {
+ if (audio && delayUs > 0) {
+ sp<AMessage> msg = new AMessage(kWhatEOS, this);
+ msg->setInt32("audioEOSGeneration", mAudioEOSGeneration);
+ msg->setInt32("finalResult", finalResult);
+ msg->post(delayUs);
+ return;
+ }
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatEOS);
notify->setInt32("audio", static_cast<int32_t>(audio));
@@ -1323,6 +1401,7 @@
if (audio) {
notifyComplete = mNotifyCompleteAudio;
mNotifyCompleteAudio = false;
+ mLastAudioMediaTimeUs = -1;
} else {
notifyComplete = mNotifyCompleteVideo;
mNotifyCompleteVideo = false;
@@ -1347,6 +1426,7 @@
flushQueue(&mAudioQueue);
++mAudioDrainGeneration;
+ ++mAudioEOSGeneration;
prepareForMediaRenderingStart_l();
// the frame count will be reset after flush.
@@ -1489,10 +1569,9 @@
mDrainAudioQueuePending = false;
mDrainVideoQueuePending = false;
- if (mHasAudio) {
- mAudioSink->pause();
- startAudioOffloadPauseTimeout();
- }
+ // Note: audio data may not have been decoded, and the AudioSink may not be opened.
+ mAudioSink->pause();
+ startAudioOffloadPauseTimeout();
ALOGV("now paused audio queue has %zu entries, video has %zu entries",
mAudioQueue.size(), mVideoQueue.size());
@@ -1503,8 +1582,9 @@
return;
}
- if (mHasAudio) {
- cancelAudioOffloadPauseTimeout();
+ // Note: audio data may not have been decoded, and the AudioSink may not be opened.
+ cancelAudioOffloadPauseTimeout();
+ if (mAudioSink->ready()) {
status_t err = mAudioSink->start();
if (err != OK) {
ALOGE("cannot start AudioSink err %d", err);
@@ -1558,70 +1638,6 @@
return mSyncQueues;
}
-// TODO: Remove unnecessary calls to getPlayedOutAudioDurationUs()
-// as it acquires locks and may query the audio driver.
-//
-// Some calls could conceivably retrieve extrapolated data instead of
-// accessing getTimestamp() or getPosition() every time a data buffer with
-// a media time is received.
-//
-// Calculate duration of played samples if played at normal rate (i.e., 1.0).
-int64_t NuPlayer::Renderer::getPlayedOutAudioDurationUs(int64_t nowUs) {
- uint32_t numFramesPlayed;
- int64_t numFramesPlayedAt;
- AudioTimestamp ts;
- static const int64_t kStaleTimestamp100ms = 100000;
-
- status_t res = mAudioSink->getTimestamp(ts);
- if (res == OK) { // case 1: mixing audio tracks and offloaded tracks.
- numFramesPlayed = ts.mPosition;
- numFramesPlayedAt =
- ts.mTime.tv_sec * 1000000LL + ts.mTime.tv_nsec / 1000;
- const int64_t timestampAge = nowUs - numFramesPlayedAt;
- if (timestampAge > kStaleTimestamp100ms) {
- // This is an audio FIXME.
- // getTimestamp returns a timestamp which may come from audio mixing threads.
- // After pausing, the MixerThread may go idle, thus the mTime estimate may
- // become stale. Assuming that the MixerThread runs 20ms, with FastMixer at 5ms,
- // the max latency should be about 25ms with an average around 12ms (to be verified).
- // For safety we use 100ms.
- ALOGV("getTimestamp: returned stale timestamp nowUs(%lld) numFramesPlayedAt(%lld)",
- (long long)nowUs, (long long)numFramesPlayedAt);
- numFramesPlayedAt = nowUs - kStaleTimestamp100ms;
- }
- //ALOGD("getTimestamp: OK %d %lld", numFramesPlayed, (long long)numFramesPlayedAt);
- } else if (res == WOULD_BLOCK) { // case 2: transitory state on start of a new track
- numFramesPlayed = 0;
- numFramesPlayedAt = nowUs;
- //ALOGD("getTimestamp: WOULD_BLOCK %d %lld",
- // numFramesPlayed, (long long)numFramesPlayedAt);
- } else { // case 3: transitory at new track or audio fast tracks.
- res = mAudioSink->getPosition(&numFramesPlayed);
- CHECK_EQ(res, (status_t)OK);
- numFramesPlayedAt = nowUs;
- numFramesPlayedAt += 1000LL * mAudioSink->latency() / 2; /* XXX */
- //ALOGD("getPosition: %u %lld", numFramesPlayed, (long long)numFramesPlayedAt);
- }
-
- //CHECK_EQ(numFramesPlayed & (1 << 31), 0); // can't be negative until 12.4 hrs, test
- int64_t durationUs = getDurationUsIfPlayedAtSampleRate(numFramesPlayed)
- + nowUs - numFramesPlayedAt;
- if (durationUs < 0) {
- // Occurs when numFramesPlayed position is very small and the following:
- // (1) In case 1, the time nowUs is computed before getTimestamp() is called and
- // numFramesPlayedAt is greater than nowUs by time more than numFramesPlayed.
- // (2) In case 3, using getPosition and adding mAudioSink->latency() to
- // numFramesPlayedAt, by a time amount greater than numFramesPlayed.
- //
- // Both of these are transitory conditions.
- ALOGV("getPlayedOutAudioDurationUs: negative duration %lld set to zero", (long long)durationUs);
- durationUs = 0;
- }
- ALOGV("getPlayedOutAudioDurationUs(%lld) nowUs(%lld) frames(%u) framesAt(%lld)",
- (long long)durationUs, (long long)nowUs, numFramesPlayed, (long long)numFramesPlayedAt);
- return durationUs;
-}
-
void NuPlayer::Renderer::onAudioTearDown(AudioTearDownReason reason) {
if (mAudioTornDown) {
return;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index 9479c31..7825f12 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -148,6 +148,7 @@
int32_t mVideoQueueGeneration;
int32_t mAudioDrainGeneration;
int32_t mVideoDrainGeneration;
+ int32_t mAudioEOSGeneration;
sp<MediaClock> mMediaClock;
float mPlaybackRate; // audio track rate
@@ -178,7 +179,8 @@
int32_t mAudioRenderingStartGeneration;
bool mRenderingDataDelivered;
- int64_t mLastPositionUpdateUs;
+ // the media timestamp of last audio sample right before EOS.
+ int64_t mLastAudioMediaTimeUs;
int32_t mAudioOffloadPauseTimeoutGeneration;
bool mAudioTornDown;
@@ -212,7 +214,6 @@
bool onDrainAudioQueue();
void drainAudioQueueUntilLastEOS();
int64_t getPendingAudioPlayoutDurationUs(int64_t nowUs);
- int64_t getPlayedOutAudioDurationUs(int64_t nowUs);
void postDrainAudioQueue_l(int64_t delayUs = 0);
void clearAnchorTime_l();
diff --git a/media/libnbaio/SourceAudioBufferProvider.cpp b/media/libnbaio/SourceAudioBufferProvider.cpp
index e21ef48..04c42c9 100644
--- a/media/libnbaio/SourceAudioBufferProvider.cpp
+++ b/media/libnbaio/SourceAudioBufferProvider.cpp
@@ -61,20 +61,30 @@
// do we need to reallocate?
if (buffer->frameCount > mSize) {
free(mAllocated);
- mAllocated = malloc(buffer->frameCount * mFrameSize);
+ // Android convention is to _not_ check the return value of malloc and friends.
+ // But in this case the calloc() can also fail due to integer overflow,
+ // so we check and recover.
+ mAllocated = calloc(buffer->frameCount, mFrameSize);
+ if (mAllocated == NULL) {
+ mSize = 0;
+ goto fail;
+ }
mSize = buffer->frameCount;
}
- // read from source
- ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts);
- if (actual > 0) {
- ALOG_ASSERT((size_t) actual <= buffer->frameCount);
- mOffset = 0;
- mRemaining = actual;
- buffer->raw = mAllocated;
- buffer->frameCount = actual;
- mGetCount = actual;
- return OK;
+ {
+ // read from source
+ ssize_t actual = mSource->read(mAllocated, buffer->frameCount, pts);
+ if (actual > 0) {
+ ALOG_ASSERT((size_t) actual <= buffer->frameCount);
+ mOffset = 0;
+ mRemaining = actual;
+ buffer->raw = mAllocated;
+ buffer->frameCount = actual;
+ mGetCount = actual;
+ return OK;
+ }
}
+fail:
buffer->raw = NULL;
buffer->frameCount = 0;
mGetCount = 0;
diff --git a/media/libstagefright/AACExtractor.cpp b/media/libstagefright/AACExtractor.cpp
index 45e8a30..19efc53 100644
--- a/media/libstagefright/AACExtractor.cpp
+++ b/media/libstagefright/AACExtractor.cpp
@@ -211,7 +211,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> AACExtractor::getTrack(size_t index) {
+sp<IMediaSource> AACExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 9d90dbd..8b1e1c3 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -67,7 +67,7 @@
}
-status_t AACWriter::addSource(const sp<MediaSource> &source) {
+status_t AACWriter::addSource(const sp<IMediaSource> &source) {
if (mInitCheck != OK) {
return mInitCheck;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 0b81b80..cb5cfe3 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -808,6 +808,10 @@
def.nBufferCountActual, bufSize, allottedSize, def.nBufferSize, asString(type),
portIndex == kPortIndexInput ? "input" : "output");
+ if (bufSize == 0 || def.nBufferCountActual > SIZE_MAX / bufSize) {
+ ALOGE("b/22885421");
+ return NO_MEMORY;
+ }
size_t totalSize = def.nBufferCountActual * bufSize;
mDealer[portIndex] = new MemoryDealer(totalSize, "ACodec");
@@ -3852,8 +3856,11 @@
params.nSliceHeight = params.nFrameHeight;
}
- // we need stride and slice-height to be non-zero
- if (params.nStride == 0 || params.nSliceHeight == 0) {
+ // we need stride and slice-height to be non-zero and sensible. These values were chosen to
+ // prevent integer overflows further down the line, and do not indicate support for
+ // 32kx32k video.
+ if (params.nStride == 0 || params.nSliceHeight == 0
+ || params.nStride > 32768 || params.nSliceHeight > 32768) {
ALOGW("cannot describe color format 0x%x = %d with stride=%u and sliceHeight=%u",
fmt, fmt, params.nStride, params.nSliceHeight);
return false;
diff --git a/media/libstagefright/AMRExtractor.cpp b/media/libstagefright/AMRExtractor.cpp
index a6fb3d8..1458802 100644
--- a/media/libstagefright/AMRExtractor.cpp
+++ b/media/libstagefright/AMRExtractor.cpp
@@ -180,7 +180,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> AMRExtractor::getTrack(size_t index) {
+sp<IMediaSource> AMRExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -309,7 +309,13 @@
buffer->release();
buffer = NULL;
- return ERROR_IO;
+ if (n < 0) {
+ return ERROR_IO;
+ } else {
+ // only partial frame is available, treat it as EOS.
+ mOffset += n;
+ return ERROR_END_OF_STREAM;
+ }
}
buffer->set_range(0, frameSize);
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index f53d7f0..961b57f 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -54,7 +54,7 @@
return mInitCheck;
}
-status_t AMRWriter::addSource(const sp<MediaSource> &source) {
+status_t AMRWriter::addSource(const sp<IMediaSource> &source) {
if (mInitCheck != OK) {
return mInitCheck;
}
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 72bae5c..9a4a350 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -30,7 +30,6 @@
MPEG4Extractor.cpp \
MPEG4Writer.cpp \
MediaAdapter.cpp \
- MediaBuffer.cpp \
MediaBufferGroup.cpp \
MediaClock.cpp \
MediaCodec.cpp \
@@ -44,7 +43,6 @@
http/MediaHTTP.cpp \
MediaMuxer.cpp \
MediaSource.cpp \
- MetaData.cpp \
NuCachedSource2.cpp \
NuMediaExtractor.cpp \
OMXClient.cpp \
diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp
index dd9d393..c977958 100644
--- a/media/libstagefright/AudioPlayer.cpp
+++ b/media/libstagefright/AudioPlayer.cpp
@@ -71,7 +71,7 @@
}
}
-void AudioPlayer::setSource(const sp<MediaSource> &source) {
+void AudioPlayer::setSource(const sp<IMediaSource> &source) {
CHECK(mSource == NULL);
mSource = source;
}
@@ -358,7 +358,7 @@
// When offloading, the OMX component is not used so this hack
// is not needed
if (!useOffload()) {
- wp<MediaSource> tmp = mSource;
+ wp<IMediaSource> tmp = mSource;
mSource.clear();
while (tmp.promote() != NULL) {
usleep(1000);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index ba59e00..98936ad 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -65,6 +65,8 @@
#define USE_SURFACE_ALLOC 1
#define FRAME_DROP_FREQ 0
+#define PROPERTY_OFFLOAD_HIWATERMARK "audio.offload.hiwatermark"
+#define PROPERTY_OFFLOAD_LOWATERMARK "audio.offload.lowatermark"
namespace android {
@@ -72,7 +74,8 @@
static int64_t kHighWaterMarkUs = 5000000ll; // 5secs
static const size_t kLowWaterMarkBytes = 40000;
static const size_t kHighWaterMarkBytes = 200000;
-
+static size_t kOffloadLowWaterMarkBytes = kLowWaterMarkBytes;
+static size_t kOffloadHighWaterMarkBytes = kHighWaterMarkBytes;
// maximum time in paused state when offloading audio decompression. When elapsed, the AudioPlayer
// is destroyed to allow the audio DSP to power down.
static int64_t kOffloadPauseMaxUs = 10000000ll;
@@ -215,6 +218,7 @@
mDecryptHandle(NULL),
mLastVideoTimeUs(-1),
mTextDriver(NULL),
+ mSelectedTimedTextTrack(-1),
mOffloadAudio(false),
mAudioTearDown(false) {
CHECK_EQ(mClient.connect(), (status_t)OK);
@@ -369,7 +373,7 @@
status_t AwesomePlayer::setDataSource_l(
const sp<DataSource> &dataSource) {
- sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+ sp<IMediaExtractor> extractor = MediaExtractor::Create(dataSource);
if (extractor == NULL) {
return UNKNOWN_ERROR;
@@ -392,7 +396,7 @@
}
}
-status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
+status_t AwesomePlayer::setDataSource_l(const sp<IMediaExtractor> &extractor) {
// Attempt to approximate overall stream bitrate by summing all
// tracks' individual bitrates, if not all of them advertise bitrate,
// we have to fail.
@@ -639,6 +643,11 @@
mMediaRenderingStartGeneration = 0;
mStartGeneration = 0;
+
+ kOffloadLowWaterMarkBytes =
+ property_get_int32(PROPERTY_OFFLOAD_LOWATERMARK, kLowWaterMarkBytes);
+ kOffloadHighWaterMarkBytes =
+ property_get_int32(PROPERTY_OFFLOAD_HIWATERMARK, kHighWaterMarkBytes);
}
void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -729,6 +738,7 @@
size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&finalStatus);
bool eos = (finalStatus != OK);
+ ALOGV("cachedDataRemaining = %zu b, eos=%d", cachedDataRemaining, eos);
if (eos) {
if (finalStatus == ERROR_END_OF_STREAM) {
notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
@@ -739,36 +749,42 @@
}
} else {
bool eos2;
+ bool knownDuration = false;
int64_t cachedDurationUs;
if (getCachedDuration_l(&cachedDurationUs, &eos2) && mDurationUs > 0) {
+ knownDuration = true;
int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
if (percentage > 100) {
percentage = 100;
}
notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
- } else {
- // We don't know the bitrate/duration of the stream, use absolute size
- // limits to maintain the cache.
+ }
+ if (!knownDuration || mOffloadAudio) {
+ // If we don't know the bitrate/duration of the stream, or are offloading
+ // decode, use absolute size limits to maintain the cache.
- if ((mFlags & PLAYING) && !eos
- && (cachedDataRemaining < kLowWaterMarkBytes)) {
- ALOGI("cache is running low (< %zu) , pausing.",
- kLowWaterMarkBytes);
+ size_t lowWatermark =
+ mOffloadAudio ? kOffloadLowWaterMarkBytes : kLowWaterMarkBytes;
+ size_t highWatermark =
+ mOffloadAudio ? kOffloadHighWaterMarkBytes : kHighWaterMarkBytes;
+
+ if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
+ ALOGI("cache is running low (< %zu) , pausing.", lowWatermark);
modifyFlags(CACHE_UNDERRUN, SET);
pause_l();
ensureCacheIsFetching_l();
sendCacheStats();
notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
+ } else if (eos || cachedDataRemaining > highWatermark) {
if (mFlags & CACHE_UNDERRUN) {
ALOGI("cache has filled up (> %zu), resuming.",
- kHighWaterMarkBytes);
+ highWatermark);
modifyFlags(CACHE_UNDERRUN, CLEAR);
play_l();
} else if (mFlags & PREPARING) {
ALOGV("cache has filled up (> %zu), prepare is done",
- kHighWaterMarkBytes);
+ highWatermark);
finishAsyncPrepare_l();
}
}
@@ -802,7 +818,7 @@
int64_t cachedDurationUs;
bool eos;
- if (getCachedDuration_l(&cachedDurationUs, &eos)) {
+ if (!mOffloadAudio && getCachedDuration_l(&cachedDurationUs, &eos)) {
ALOGV("cachedDurationUs = %.2f secs, eos=%d",
cachedDurationUs / 1E6, eos);
@@ -829,7 +845,8 @@
}
}
- if (mFlags & (PLAYING | PREPARING | CACHE_UNDERRUN)) {
+ if ( ((mFlags & PLAYING) && !eos) ||
+ (mFlags & (PREPARING | CACHE_UNDERRUN)) ) {
postBufferingEvent_l();
}
}
@@ -1353,7 +1370,7 @@
// The following hack is necessary to ensure that the OMX
// component is completely released by the time we may try
// to instantiate it again.
- wp<MediaSource> tmp = mVideoSource;
+ wp<IMediaSource> tmp = mVideoSource;
mVideoSource.clear();
while (tmp.promote() != NULL) {
usleep(1000);
@@ -1517,13 +1534,13 @@
}
}
-void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
+void AwesomePlayer::setAudioSource(sp<IMediaSource> source) {
CHECK(source != NULL);
mAudioTrack = source;
}
-void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<MediaSource>& source) {
+void AwesomePlayer::addTextSource_l(size_t trackIndex, const sp<IMediaSource>& source) {
CHECK(source != NULL);
if (mTextDriver == NULL) {
@@ -1609,7 +1626,7 @@
return mAudioSource != NULL ? OK : UNKNOWN_ERROR;
}
-void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
+void AwesomePlayer::setVideoSource(sp<IMediaSource> source) {
CHECK(source != NULL);
mVideoTrack = source;
@@ -2392,7 +2409,7 @@
return UNKNOWN_ERROR;
}
- sp<MediaExtractor> extractor;
+ sp<IMediaExtractor> extractor;
if (isWidevineStreaming) {
String8 mimeType;
@@ -2679,6 +2696,7 @@
} else {
reply->writeInt32(MEDIA_TRACK_TYPE_UNKNOWN);
}
+ reply->writeString16(String16(mime));
const char *lang;
if (!meta->findCString(kKeyMediaLanguage, &lang)) {
@@ -2694,7 +2712,7 @@
}
status_t AwesomePlayer::selectAudioTrack_l(
- const sp<MediaSource>& source, size_t trackIndex) {
+ const sp<IMediaSource>& source, size_t trackIndex) {
ALOGI("selectAudioTrack_l: trackIndex=%zu, mFlags=0x%x", trackIndex, mFlags);
@@ -2813,12 +2831,14 @@
mTextDriver->start();
modifyFlags(TEXT_RUNNING, SET);
}
+ mSelectedTimedTextTrack = trackIndex;
}
} else {
err = mTextDriver->unselectTrack(trackIndex);
if (err == OK) {
modifyFlags(TEXTPLAYER_INITIALIZED, CLEAR);
modifyFlags(TEXT_RUNNING, CLEAR);
+ mSelectedTimedTextTrack = -1;
}
}
return err;
@@ -2903,6 +2923,15 @@
int trackIndex = request.readInt32();
return selectTrack(trackIndex, false /* select */);
}
+ case INVOKE_ID_GET_SELECTED_TRACK:
+ {
+ int trackType = request.readInt32();
+ if (trackType == MEDIA_TRACK_TYPE_TIMEDTEXT) {
+ reply->writeInt32(mSelectedTimedTextTrack);
+ return mSelectedTimedTextTrack;
+ }
+
+ }
default:
{
return ERROR_UNSUPPORTED;
diff --git a/media/libstagefright/CallbackDataSource.cpp b/media/libstagefright/CallbackDataSource.cpp
index e17fdf8..4c0a578 100644
--- a/media/libstagefright/CallbackDataSource.cpp
+++ b/media/libstagefright/CallbackDataSource.cpp
@@ -64,7 +64,7 @@
mIDataSource->readAt(offset + totalNumRead, numToRead);
// A negative return value represents an error. Pass it on.
if (numRead < 0) {
- return numRead;
+ return numRead == ERROR_END_OF_STREAM && totalNumRead > 0 ? totalNumRead : numRead;
}
// A zero return value signals EOS. Return the bytes read so far.
if (numRead == 0) {
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index 66280da..dab623b 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -22,6 +22,9 @@
#include <OMX_Component.h>
#include <binder/IPCThreadState.h>
+#include <binder/MemoryBase.h>
+#include <binder/MemoryHeapBase.h>
+#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/MediaDefs.h>
@@ -503,6 +506,77 @@
return err;
}
+status_t CameraSource::initBufferQueue(uint32_t width, uint32_t height,
+ uint32_t format, android_dataspace dataSpace, uint32_t bufferCount) {
+ ALOGV("initBufferQueue");
+
+ if (mVideoBufferConsumer != nullptr || mVideoBufferProducer != nullptr) {
+ ALOGE("%s: Buffer queue already exists", __FUNCTION__);
+ return ALREADY_EXISTS;
+ }
+
+ // Create a buffer queue.
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer);
+
+ uint32_t usage = GRALLOC_USAGE_SW_READ_OFTEN;
+ if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ usage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
+ }
+
+ bufferCount += kConsumerBufferCount;
+
+ mVideoBufferConsumer = new BufferItemConsumer(consumer, usage, bufferCount);
+ mVideoBufferConsumer->setName(String8::format("StageFright-CameraSource"));
+ mVideoBufferProducer = producer;
+
+ status_t res = mVideoBufferConsumer->setDefaultBufferSize(width, height);
+ if (res != OK) {
+ ALOGE("%s: Could not set buffer dimensions %dx%d: %s (%d)", __FUNCTION__, width, height,
+ strerror(-res), res);
+ return res;
+ }
+
+ res = mVideoBufferConsumer->setDefaultBufferFormat(format);
+ if (res != OK) {
+ ALOGE("%s: Could not set buffer format %d: %s (%d)", __FUNCTION__, format,
+ strerror(-res), res);
+ return res;
+ }
+
+ res = mVideoBufferConsumer->setDefaultBufferDataSpace(dataSpace);
+ if (res != OK) {
+ ALOGE("%s: Could not set data space %d: %s (%d)", __FUNCTION__, dataSpace,
+ strerror(-res), res);
+ return res;
+ }
+
+ res = mCamera->setVideoTarget(mVideoBufferProducer);
+ if (res != OK) {
+ ALOGE("%s: Failed to set video target: %s (%d)", __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ // Create memory heap to store buffers as VideoNativeMetadata.
+ size_t bufferSize = sizeof(VideoNativeMetadata);
+ mMemoryHeapBase = new MemoryHeapBase(bufferSize * bufferCount, 0,
+ "StageFright-CameraSource-BufferHeap");
+ for (uint32_t i = 0; i < bufferCount; i++) {
+ mMemoryBases.push_back(new MemoryBase(mMemoryHeapBase, i * bufferSize, bufferSize));
+ }
+
+ mBufferQueueListener = new BufferQueueListener(mVideoBufferConsumer, this);
+ res = mBufferQueueListener->run("CameraSource-BufferQueueListener");
+ if (res != OK) {
+ ALOGE("%s: Could not run buffer queue listener thread: %s (%d)", __FUNCTION__,
+ strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
status_t CameraSource::initWithCameraAccess(
const sp<ICamera>& camera,
const sp<ICameraRecordingProxy>& proxy,
@@ -551,12 +625,23 @@
CHECK_EQ((status_t)OK, mCamera->setPreviewTarget(mSurface));
}
- // By default, do not store metadata in video buffers
- mIsMetaDataStoredInVideoBuffers = false;
- mCamera->storeMetaDataInBuffers(false);
+ // By default, store real data in video buffers.
+ mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV;
if (storeMetaDataInVideoBuffers) {
- if (OK == mCamera->storeMetaDataInBuffers(true)) {
- mIsMetaDataStoredInVideoBuffers = true;
+ if (OK == mCamera->setVideoBufferMode(ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE)) {
+ mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE;
+ } else if (OK == mCamera->setVideoBufferMode(
+ ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA)) {
+ mVideoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA;
+ }
+ }
+
+ if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV) {
+ err = mCamera->setVideoBufferMode(ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV);
+ if (err != OK) {
+ ALOGE("%s: Setting video buffer mode to VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV failed: "
+ "%s (err=%d)", __FUNCTION__, strerror(-err), err);
+ return err;
}
}
@@ -596,28 +681,41 @@
// will connect to the camera in ICameraRecordingProxy::startRecording.
int64_t token = IPCThreadState::self()->clearCallingIdentity();
status_t err;
- if (mNumInputBuffers > 0) {
+
+ if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ // Initialize buffer queue.
+ err = initBufferQueue(mVideoSize.width, mVideoSize.height, mEncoderFormat,
+ (android_dataspace_t)mEncoderDataSpace,
+ mNumInputBuffers > 0 ? mNumInputBuffers : 1);
+ if (err != OK) {
+ ALOGE("%s: Failed to initialize buffer queue: %s (err=%d)", __FUNCTION__,
+ strerror(-err), err);
+ return err;
+ }
+ } else {
+ if (mNumInputBuffers > 0) {
+ err = mCamera->sendCommand(
+ CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
+
+ // This could happen for CameraHAL1 clients; thus the failure is
+ // not a fatal error
+ if (err != OK) {
+ ALOGW("Failed to set video buffer count to %d due to %d",
+ mNumInputBuffers, err);
+ }
+ }
+
err = mCamera->sendCommand(
- CAMERA_CMD_SET_VIDEO_BUFFER_COUNT, mNumInputBuffers, 0);
+ CAMERA_CMD_SET_VIDEO_FORMAT, mEncoderFormat, mEncoderDataSpace);
// This could happen for CameraHAL1 clients; thus the failure is
// not a fatal error
if (err != OK) {
- ALOGW("Failed to set video buffer count to %d due to %d",
- mNumInputBuffers, err);
+ ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
+ mEncoderFormat, mEncoderDataSpace, err);
}
}
- err = mCamera->sendCommand(
- CAMERA_CMD_SET_VIDEO_FORMAT, mEncoderFormat, mEncoderDataSpace);
-
- // This could happen for CameraHAL1 clients; thus the failure is
- // not a fatal error
- if (err != OK) {
- ALOGW("Failed to set video encoder format/dataspace to %d, %d due to %d",
- mEncoderFormat, mEncoderDataSpace, err);
- }
-
err = OK;
if (mCameraFlags & FLAGS_HOT_CAMERA) {
mCamera->unlock();
@@ -771,6 +869,14 @@
CHECK_EQ(mNumFramesReceived, mNumFramesEncoded + mNumFramesDropped);
}
+ if (mBufferQueueListener != nullptr) {
+ mBufferQueueListener->requestExit();
+ mBufferQueueListener->join();
+ mBufferQueueListener.clear();
+ }
+
+ mVideoBufferConsumer.clear();
+ mVideoBufferProducer.clear();
releaseCamera();
ALOGD("reset: X");
@@ -779,7 +885,33 @@
void CameraSource::releaseRecordingFrame(const sp<IMemory>& frame) {
ALOGV("releaseRecordingFrame");
- if (mCameraRecordingProxy != NULL) {
+
+ if (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ // Return the buffer to buffer queue in VIDEO_BUFFER_MODE_BUFFER_QUEUE mode.
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = frame->getMemory(&offset, &size);
+ if (heap->getHeapID() != mMemoryHeapBase->getHeapID()) {
+ ALOGE("%s: Mismatched heap ID, ignoring release (got %x, expected %x)", __FUNCTION__,
+ heap->getHeapID(), mMemoryHeapBase->getHeapID());
+ return;
+ }
+
+ VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
+ (uint8_t*)heap->getBase() + offset);
+
+ // Find the corresponding buffer item for the native window buffer.
+ ssize_t index = mReceivedBufferItemMap.indexOfKey(payload->pBuffer);
+ if (index == NAME_NOT_FOUND) {
+ ALOGE("%s: Couldn't find buffer item for %p", __FUNCTION__, payload->pBuffer);
+ return;
+ }
+
+ BufferItem buffer = mReceivedBufferItemMap.valueAt(index);
+ mReceivedBufferItemMap.removeItemsAt(index);
+ mVideoBufferConsumer->releaseBuffer(buffer);
+ mMemoryBases.push_back(frame);
+ } else if (mCameraRecordingProxy != NULL) {
mCameraRecordingProxy->releaseRecordingFrame(frame);
} else if (mCamera != NULL) {
int64_t token = IPCThreadState::self()->clearCallingIdentity();
@@ -871,29 +1003,23 @@
return OK;
}
-void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
- int32_t msgType __unused, const sp<IMemory> &data) {
- ALOGV("dataCallbackTimestamp: timestamp %lld us", (long long)timestampUs);
- Mutex::Autolock autoLock(mLock);
+bool CameraSource::shouldSkipFrameLocked(int64_t timestampUs) {
if (!mStarted || (mNumFramesReceived == 0 && timestampUs < mStartTimeUs)) {
ALOGV("Drop frame at %lld/%lld us", (long long)timestampUs, (long long)mStartTimeUs);
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
// May need to skip frame or modify timestamp. Currently implemented
// by the subclass CameraSourceTimeLapse.
if (skipCurrentFrame(timestampUs)) {
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
if (mNumFramesReceived > 0) {
if (timestampUs <= mLastFrameTimestampUs) {
ALOGW("Dropping frame with backward timestamp %lld (last %lld)",
(long long)timestampUs, (long long)mLastFrameTimestampUs);
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
if (timestampUs - mLastFrameTimestampUs > mGlitchDurationThresholdUs) {
++mNumGlitches;
@@ -908,12 +1034,25 @@
if (timestampUs < mStartTimeUs) {
// Frame was captured before recording was started
// Drop it without updating the statistical data.
- releaseOneRecordingFrame(data);
- return;
+ return true;
}
mStartTimeUs = timestampUs - mStartTimeUs;
}
}
+
+ return false;
+}
+
+void CameraSource::dataCallbackTimestamp(int64_t timestampUs,
+ int32_t msgType __unused, const sp<IMemory> &data) {
+ ALOGV("dataCallbackTimestamp: timestamp %lld us", (long long)timestampUs);
+ Mutex::Autolock autoLock(mLock);
+
+ if (shouldSkipFrameLocked(timestampUs)) {
+ releaseOneRecordingFrame(data);
+ return;
+ }
+
++mNumFramesReceived;
CHECK(data != NULL && data->size() > 0);
@@ -925,9 +1064,97 @@
mFrameAvailableCondition.signal();
}
+CameraSource::BufferQueueListener::BufferQueueListener(const sp<BufferItemConsumer>& consumer,
+ const sp<CameraSource>& cameraSource) {
+ mConsumer = consumer;
+ mConsumer->setFrameAvailableListener(this);
+ mCameraSource = cameraSource;
+}
+
+void CameraSource::BufferQueueListener::onFrameAvailable(const BufferItem& /*item*/) {
+ ALOGV("%s: onFrameAvailable", __FUNCTION__);
+
+ Mutex::Autolock l(mLock);
+
+ if (!mFrameAvailable) {
+ mFrameAvailable = true;
+ mFrameAvailableSignal.signal();
+ }
+}
+
+bool CameraSource::BufferQueueListener::threadLoop() {
+ if (mConsumer == nullptr || mCameraSource == nullptr) {
+ return false;
+ }
+
+ {
+ Mutex::Autolock l(mLock);
+ while (!mFrameAvailable) {
+ if (mFrameAvailableSignal.waitRelative(mLock, kFrameAvailableTimeout) == TIMED_OUT) {
+ return true;
+ }
+ }
+ mFrameAvailable = false;
+ }
+
+ BufferItem buffer;
+ while (mConsumer->acquireBuffer(&buffer, 0) == OK) {
+ mCameraSource->processBufferQueueFrame(buffer);
+ }
+
+ return true;
+}
+
+void CameraSource::processBufferQueueFrame(const BufferItem& buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ int64_t timestampUs = buffer.mTimestamp / 1000;
+ if (shouldSkipFrameLocked(timestampUs)) {
+ mVideoBufferConsumer->releaseBuffer(buffer);
+ return;
+ }
+
+ if (mMemoryBases.empty()) {
+ ALOGW("%s: No available memory base. Dropping a recording frame.", __FUNCTION__);
+ mVideoBufferConsumer->releaseBuffer(buffer);
+ return;
+ }
+
+ ++mNumFramesReceived;
+
+ // Find a available memory slot to store the buffer as VideoNativeMetadata.
+ sp<IMemory> data = *mMemoryBases.begin();
+ mMemoryBases.erase(mMemoryBases.begin());
+
+ ssize_t offset;
+ size_t size;
+ sp<IMemoryHeap> heap = data->getMemory(&offset, &size);
+ VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
+ (uint8_t*)heap->getBase() + offset);
+ memset(payload, 0, sizeof(VideoNativeMetadata));
+ payload->eType = kMetadataBufferTypeANWBuffer;
+ payload->pBuffer = buffer.mGraphicBuffer->getNativeBuffer();
+ payload->nFenceFd = -1;
+
+ // Add the mapping so we can find the corresponding buffer item to release to the buffer queue
+ // when the encoder returns the native window buffer.
+ mReceivedBufferItemMap.add(payload->pBuffer, buffer);
+
+ mFramesReceived.push_back(data);
+ int64_t timeUs = mStartTimeUs + (timestampUs - mFirstFrameTimeUs);
+ mFrameTimes.push_back(timeUs);
+ ALOGV("initial delay: %" PRId64 ", current time stamp: %" PRId64,
+ mStartTimeUs, timeUs);
+ mFrameAvailableCondition.signal();
+}
+
bool CameraSource::isMetaDataStoredInVideoBuffers() const {
ALOGV("isMetaDataStoredInVideoBuffers");
- return mIsMetaDataStoredInVideoBuffers;
+
+ // Output buffers will contain metadata if camera sends us buffer in metadata mode or via
+ // buffer queue.
+ return (mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA ||
+ mVideoBufferMode == ICamera::VIDEO_BUFFER_MODE_BUFFER_QUEUE);
}
CameraSource::ProxyListener::ProxyListener(const sp<CameraSource>& source) {
diff --git a/media/libstagefright/DRMExtractor.cpp b/media/libstagefright/DRMExtractor.cpp
index 9cb6e86..255dcd0 100644
--- a/media/libstagefright/DRMExtractor.cpp
+++ b/media/libstagefright/DRMExtractor.cpp
@@ -35,7 +35,7 @@
class DRMSource : public MediaSource {
public:
- DRMSource(const sp<MediaSource> &mediaSource,
+ DRMSource(const sp<IMediaSource> &mediaSource,
const sp<DecryptHandle> &decryptHandle,
DrmManagerClient *managerClient,
int32_t trackId, DrmBuffer *ipmpBox);
@@ -50,7 +50,7 @@
virtual ~DRMSource();
private:
- sp<MediaSource> mOriginalMediaSource;
+ sp<IMediaSource> mOriginalMediaSource;
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient* mDrmManagerClient;
size_t mTrackId;
@@ -64,7 +64,7 @@
////////////////////////////////////////////////////////////////////////////////
-DRMSource::DRMSource(const sp<MediaSource> &mediaSource,
+DRMSource::DRMSource(const sp<IMediaSource> &mediaSource,
const sp<DecryptHandle> &decryptHandle,
DrmManagerClient *managerClient,
int32_t trackId, DrmBuffer *ipmpBox)
@@ -247,8 +247,8 @@
return mOriginalExtractor->countTracks();
}
-sp<MediaSource> DRMExtractor::getTrack(size_t index) {
- sp<MediaSource> originalMediaSource = mOriginalExtractor->getTrack(index);
+sp<IMediaSource> DRMExtractor::getTrack(size_t index) {
+ sp<IMediaSource> originalMediaSource = mOriginalExtractor->getTrack(index);
originalMediaSource->getFormat()->setInt32(kKeyIsDRM, 1);
int32_t trackID;
@@ -258,8 +258,9 @@
ipmpBox.data = mOriginalExtractor->getDrmTrackInfo(trackID, &(ipmpBox.length));
CHECK(ipmpBox.length > 0);
- return new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient,
- trackID, &ipmpBox);
+ return interface_cast<IMediaSource>(
+ new DRMSource(originalMediaSource, mDecryptHandle, mDrmManagerClient,
+ trackID, &ipmpBox));
}
sp<MetaData> DRMExtractor::getTrackMetaData(size_t index, uint32_t flags) {
diff --git a/media/libstagefright/DataSource.cpp b/media/libstagefright/DataSource.cpp
index 5020c6c..163a527 100644
--- a/media/libstagefright/DataSource.cpp
+++ b/media/libstagefright/DataSource.cpp
@@ -48,6 +48,8 @@
#include <cutils/properties.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
bool DataSource::getUInt16(off64_t offset, uint16_t *x) {
@@ -173,7 +175,10 @@
RegisterSniffer_l(SniffMP3);
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffMPEG2PS);
- RegisterSniffer_l(SniffWVM);
+ if (getuid() == AID_MEDIA) {
+ // WVM only in the media server process
+ RegisterSniffer_l(SniffWVM);
+ }
RegisterSniffer_l(SniffMidi);
char value[PROPERTY_VALUE_MAX];
diff --git a/media/libstagefright/FLACExtractor.cpp b/media/libstagefright/FLACExtractor.cpp
index 89a91f7..6e99d02 100644
--- a/media/libstagefright/FLACExtractor.cpp
+++ b/media/libstagefright/FLACExtractor.cpp
@@ -807,7 +807,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> FLACExtractor::getTrack(size_t index)
+sp<IMediaSource> FLACExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
diff --git a/media/libstagefright/FileSource.cpp b/media/libstagefright/FileSource.cpp
index 37053ec..5d762d8 100644
--- a/media/libstagefright/FileSource.cpp
+++ b/media/libstagefright/FileSource.cpp
@@ -20,6 +20,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/FileSource.h>
+#include <media/stagefright/Utils.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/types.h>
@@ -38,6 +39,7 @@
mDrmBufSize(0),
mDrmBuf(NULL){
+ ALOGV("%s", filename);
mFd = open(filename, O_LARGEFILE | O_RDONLY);
if (mFd >= 0) {
@@ -56,6 +58,9 @@
mDrmBufOffset(0),
mDrmBufSize(0),
mDrmBuf(NULL){
+ ALOGV("fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) length);
+
CHECK(offset >= 0);
CHECK(length >= 0);
}
@@ -99,8 +104,8 @@
if (offset >= mLength) {
return 0; // read beyond EOF.
}
- int64_t numAvailable = mLength - offset;
- if ((int64_t)size > numAvailable) {
+ uint64_t numAvailable = mLength - offset;
+ if ((uint64_t)size > numAvailable) {
size = numAvailable;
}
}
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index 2e54e8c..7240e1a 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -400,7 +400,7 @@
return mInitCheck != OK ? 0 : 1;
}
-sp<MediaSource> MP3Extractor::getTrack(size_t index) {
+sp<IMediaSource> MP3Extractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index ef07aa0..a9e8846 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -35,7 +35,7 @@
namespace android {
struct MPEG2TSWriter::SourceInfo : public AHandler {
- SourceInfo(const sp<MediaSource> &source);
+ SourceInfo(const sp<IMediaSource> &source);
void start(const sp<AMessage> ¬ify);
void stop();
@@ -69,7 +69,7 @@
kWhatRead = 'read',
};
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<ALooper> mLooper;
sp<AMessage> mNotify;
@@ -93,7 +93,7 @@
DISALLOW_EVIL_CONSTRUCTORS(SourceInfo);
};
-MPEG2TSWriter::SourceInfo::SourceInfo(const sp<MediaSource> &source)
+MPEG2TSWriter::SourceInfo::SourceInfo(const sp<IMediaSource> &source)
: mSource(source),
mLooper(new ALooper),
mEOSReceived(false),
@@ -523,7 +523,7 @@
}
}
-status_t MPEG2TSWriter::addSource(const sp<MediaSource> &source) {
+status_t MPEG2TSWriter::addSource(const sp<IMediaSource> &source) {
CHECK(!mStarted);
sp<MetaData> meta = source->getFormat();
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
old mode 100755
new mode 100644
index bfdff38..a6275ba
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -766,6 +766,11 @@
status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
ALOGV("entering parseChunk %lld/%d", (long long)*offset, depth);
+
+ if (*offset < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
uint32_t hdr[2];
if (mDataSource->readAt(*offset, hdr, 8) < 8) {
return ERROR_IO;
@@ -831,7 +836,12 @@
PathAdder autoAdder(&mPath, chunk_type);
- off64_t chunk_data_size = *offset + chunk_size - data_offset;
+ // (data_offset - *offset) is either 8 or 16
+ off64_t chunk_data_size = chunk_size - (data_offset - *offset);
+ if (chunk_data_size < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
if (chunk_type != FOURCC('c', 'p', 'r', 't')
&& chunk_type != FOURCC('c', 'o', 'v', 'r')
@@ -929,6 +939,11 @@
}
if (isTrack) {
+ int32_t trackId;
+ // There must be exact one track header per track.
+ if (!mLastTrack->meta->findInt32(kKeyTrackID, &trackId)) {
+ mLastTrack->skipTrack = true;
+ }
if (mLastTrack->skipTrack) {
Track *cur = mFirstTrack;
@@ -2820,7 +2835,7 @@
}
}
-sp<MediaSource> MPEG4Extractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG4Extractor::getTrack(size_t index) {
status_t err;
if ((err = readMetaData()) != OK) {
return NULL;
@@ -2851,10 +2866,46 @@
break;
}
}
+ } else {
+ ALOGE("b/21657957");
+ return NULL;
}
ALOGV("getTrack called, pssh: %zu", mPssh.size());
+ const char *mime;
+ if (!track->meta->findCString(kKeyMIMEType, &mime)) {
+ return NULL;
+ }
+
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!track->meta->findData(kKeyAVCC, &type, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ if (size < 7 || ptr[0] != 1) { // configurationVersion == 1
+ return NULL;
+ }
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!track->meta->findData(kKeyHVCC, &type, &data, &size)) {
+ return NULL;
+ }
+
+ const uint8_t *ptr = (const uint8_t *)data;
+
+ if (size < 22 || ptr[0] != 1) { // configurationVersion == 1
+ return NULL;
+ }
+ }
+
return new MPEG4Source(this,
track->meta, mDataSource, track->timescale, track->sampleTable,
mSidxEntries, trex, mMoofOffset);
@@ -3310,7 +3361,7 @@
const uint8_t *ptr = (const uint8_t *)data;
- CHECK(size >= 7);
+ CHECK(size >= 22);
CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1
mNALLengthSize = 1 + (ptr[14 + 7] & 3);
@@ -4690,12 +4741,18 @@
// The smallest valid chunk is 16 bytes long in this case.
return false;
}
+
} else if (chunkSize < 8) {
// The smallest valid chunk is 8 bytes long.
return false;
}
- off64_t chunkDataSize = offset + chunkSize - chunkDataOffset;
+ // (data_offset - offset) is either 8 or 16
+ off64_t chunkDataSize = chunkSize - (chunkDataOffset - offset);
+ if (chunkDataSize < 0) {
+ ALOGE("b/23540914");
+ return ERROR_MALFORMED;
+ }
char chunkstring[5];
MakeFourCCString(chunkType, chunkstring);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 78d4fb1..ea4a7ac 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -75,7 +75,7 @@
class MPEG4Writer::Track {
public:
- Track(MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId);
+ Track(MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId);
~Track();
@@ -228,7 +228,7 @@
MPEG4Writer *mOwner;
sp<MetaData> mMeta;
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
volatile bool mDone;
volatile bool mPaused;
volatile bool mResumed;
@@ -470,7 +470,7 @@
return NULL;
}
-status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
+status_t MPEG4Writer::addSource(const sp<IMediaSource> &source) {
Mutex::Autolock l(mLock);
if (mStarted) {
ALOGE("Attempt to add source AFTER recording is started");
@@ -1436,7 +1436,7 @@
////////////////////////////////////////////////////////////////////////////////
MPEG4Writer::Track::Track(
- MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
+ MPEG4Writer *owner, const sp<IMediaSource> &source, size_t trackId)
: mOwner(owner),
mMeta(source->getFormat()),
mSource(source),
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 2641e4e..3aa0061 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -25,6 +25,10 @@
namespace android {
+// Maximum allowed time backwards from anchor change.
+// If larger than this threshold, it's treated as discontinuity.
+static const int64_t kAnchorFluctuationAllowedUs = 10000ll;
+
MediaClock::MediaClock()
: mAnchorTimeMediaUs(-1),
mAnchorTimeRealUs(-1),
@@ -64,9 +68,20 @@
ALOGW("reject anchor time since it leads to negative media time.");
return;
}
+
+ if (maxTimeMediaUs != -1) {
+ mMaxTimeMediaUs = maxTimeMediaUs;
+ }
+ if (mAnchorTimeRealUs != -1) {
+ int64_t oldNowMediaUs =
+ mAnchorTimeMediaUs + (nowUs - mAnchorTimeRealUs) * (double)mPlaybackRate;
+ if (nowMediaUs < oldNowMediaUs
+ && nowMediaUs > oldNowMediaUs - kAnchorFluctuationAllowedUs) {
+ return;
+ }
+ }
mAnchorTimeRealUs = nowUs;
mAnchorTimeMediaUs = nowMediaUs;
- mMaxTimeMediaUs = maxTimeMediaUs;
}
void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index c2ffdf2..77722be 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -423,6 +423,13 @@
if (!format->findInt32("rotation-degrees", &mRotationDegrees)) {
mRotationDegrees = 0;
}
+
+ // Prevent possible integer overflow in downstream code.
+ if (mInitIsEncoder
+ && (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
+ ALOGE("buffer size is too big, width=%d, height=%d", mVideoWidth, mVideoHeight);
+ return BAD_VALUE;
+ }
}
msg->setMessage("format", format);
@@ -681,6 +688,7 @@
const uint8_t key[16],
const uint8_t iv[16],
CryptoPlugin::Mode mode,
+ const CryptoPlugin::Pattern &pattern,
int64_t presentationTimeUs,
uint32_t flags,
AString *errorDetailMsg) {
@@ -696,6 +704,8 @@
msg->setPointer("key", (void *)key);
msg->setPointer("iv", (void *)iv);
msg->setInt32("mode", mode);
+ msg->setInt32("encryptBlocks", pattern.mEncryptBlocks);
+ msg->setInt32("skipBlocks", pattern.mSkipBlocks);
msg->setInt64("timeUs", presentationTimeUs);
msg->setInt32("flags", flags);
msg->setPointer("errorDetailMsg", errorDetailMsg);
@@ -873,33 +883,54 @@
size_t portIndex, size_t index,
sp<ABuffer> *buffer, sp<AMessage> *format) {
// use mutex instead of a context switch
-
if (mReleasedByResourceManager) {
+ ALOGE("getBufferAndFormat - resource already released");
return DEAD_OBJECT;
}
+ if (buffer == NULL) {
+ ALOGE("getBufferAndFormat - null ABuffer");
+ return INVALID_OPERATION;
+ }
+
+ if (format == NULL) {
+ ALOGE("getBufferAndFormat - null AMessage");
+ return INVALID_OPERATION;
+ }
+
buffer->clear();
format->clear();
+
if (!isExecuting()) {
+ ALOGE("getBufferAndFormat - not executing");
return INVALID_OPERATION;
}
// we do not want mPortBuffers to change during this section
// we also don't want mOwnedByClient to change during this
Mutex::Autolock al(mBufferLock);
+
Vector<BufferInfo> *buffers = &mPortBuffers[portIndex];
- if (index < buffers->size()) {
- const BufferInfo &info = buffers->itemAt(index);
- if (info.mOwnedByClient) {
- // by the time buffers array is initialized, crypto is set
- if (portIndex == kPortIndexInput && mCrypto != NULL) {
- *buffer = info.mEncryptedData;
- } else {
- *buffer = info.mData;
- }
- *format = info.mFormat;
- }
+ if (index >= buffers->size()) {
+ ALOGE("getBufferAndFormat - trying to get buffer with "
+ "bad index (index=%zu buffer_size=%zu)", index, buffers->size());
+ return INVALID_OPERATION;
}
+
+ const BufferInfo &info = buffers->itemAt(index);
+ if (!info.mOwnedByClient) {
+ ALOGE("getBufferAndFormat - invalid operation "
+ "(the index %zu is not owned by client)", index);
+ return INVALID_OPERATION;
+ }
+
+ // by the time buffers array is initialized, crypto is set
+ *buffer = (portIndex == kPortIndexInput && mCrypto != NULL) ?
+ info.mEncryptedData :
+ info.mData;
+
+ *format = info.mFormat;
+
return OK;
}
@@ -2424,11 +2455,16 @@
AString *errorDetailMsg;
CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
+ CryptoPlugin::Pattern pattern;
+ CHECK(msg->findInt32("encryptBlocks", (int32_t *)&pattern.mEncryptBlocks));
+ CHECK(msg->findInt32("skipBlocks", (int32_t *)&pattern.mSkipBlocks));
+
ssize_t result = mCrypto->decrypt(
(mFlags & kFlagIsSecure) != 0,
key,
iv,
mode,
+ pattern,
info->mSharedEncryptedBuffer,
offset,
subSamples,
@@ -2789,25 +2825,15 @@
}
void MediaCodec::updateBatteryStat() {
+ if (!mIsVideo) {
+ return;
+ }
+
if (mState == CONFIGURED && !mBatteryStatNotified) {
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
-
- if (mIsVideo) {
- notifier.noteStartVideo();
- } else {
- notifier.noteStartAudio();
- }
-
+ BatteryNotifier::getInstance().noteStartVideo();
mBatteryStatNotified = true;
} else if (mState == UNINITIALIZED && mBatteryStatNotified) {
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
-
- if (mIsVideo) {
- notifier.noteStopVideo();
- } else {
- notifier.noteStopAudio();
- }
-
+ BatteryNotifier::getInstance().noteStopVideo();
mBatteryStatNotified = false;
}
}
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index 7f9f824..d579695 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -274,6 +274,12 @@
return NULL;
}
+void MediaCodecSource::setInputBufferTimeOffset(int64_t timeOffsetUs) {
+ sp<AMessage> msg = new AMessage(kWhatSetInputBufferTimeOffset, mReflector);
+ msg->setInt64("time-offset-us", timeOffsetUs);
+ postSynchronouslyAndReturnError(msg);
+}
+
status_t MediaCodecSource::start(MetaData* params) {
sp<AMessage> msg = new AMessage(kWhatStart, mReflector);
msg->setObject("meta", params);
@@ -348,6 +354,7 @@
mEncoderFormat(0),
mEncoderDataSpace(0),
mGraphicBufferConsumer(consumer),
+ mInputBufferTimeOffsetUs(0),
mFirstSampleTimeUs(-1ll),
mEncoderReachedEOS(false),
mErrorCode(OK) {
@@ -568,6 +575,7 @@
if (mbuf != NULL) {
CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
+ timeUs += mInputBufferTimeOffsetUs;
// push decoding time for video, or drift time for audio
if (mIsVideo) {
@@ -749,6 +757,9 @@
if (mIsVideo) {
int64_t decodingTimeUs;
if (mFlags & FLAG_USE_SURFACE_INPUT) {
+ // Time offset is not applied at
+ // feedEncoderInputBuffer() in surface input case.
+ timeUs += mInputBufferTimeOffsetUs;
// GraphicBufferSource is supposed to discard samples
// queued before start, and offset timeUs by start time
CHECK_GE(timeUs, 0ll);
@@ -852,7 +863,7 @@
}
case kWhatPause:
{
- if (mFlags && FLAG_USE_SURFACE_INPUT) {
+ if (mFlags & FLAG_USE_SURFACE_INPUT) {
suspend();
} else {
CHECK(mPuller != NULL);
@@ -860,6 +871,17 @@
}
break;
}
+ case kWhatSetInputBufferTimeOffset:
+ {
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ CHECK(msg->findInt64("time-offset-us", &mInputBufferTimeOffsetUs));
+
+ sp<AMessage> response = new AMessage;
+ response->postReply(replyID);
+ break;
+ }
default:
TRESPASS();
}
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index e21fe6e..99e58f1 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MediaExtractor"
#include <utils/Log.h>
+#include <inttypes.h>
+#include <pwd.h>
#include "include/AMRExtractor.h"
#include "include/MP3Extractor.h"
@@ -33,15 +35,34 @@
#include "matroska/MatroskaExtractor.h"
+#include <binder/IServiceManager.h>
+#include <binder/MemoryDealer.h>
+
+#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
+#include <media/IMediaExtractorService.h>
+#include <cutils/properties.h>
#include <utils/String8.h>
+#include <private/android_filesystem_config.h>
+
namespace android {
+MediaExtractor::MediaExtractor():
+ mIsDrm(false) {
+ if (!LOG_NDEBUG) {
+ uid_t uid = getuid();
+ struct passwd *pw = getpwuid(uid);
+ ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
+ }
+
+}
+
+
sp<MetaData> MediaExtractor::getMetaData() {
return new MetaData;
}
@@ -50,9 +71,102 @@
return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_PAUSE | CAN_SEEK;
}
+
+
+class RemoteDataSource : public BnDataSource {
+public:
+ enum {
+ kBufferSize = 64 * 1024,
+ };
+
+ static sp<IDataSource> wrap(const sp<DataSource> &source);
+ virtual ~RemoteDataSource();
+
+ virtual sp<IMemory> getIMemory();
+ virtual ssize_t readAt(off64_t offset, size_t size);
+ virtual status_t getSize(off64_t* size);
+ virtual void close();
+
+private:
+ sp<IMemory> mMemory;
+ sp<DataSource> mSource;
+ RemoteDataSource(const sp<DataSource> &source);
+ DISALLOW_EVIL_CONSTRUCTORS(RemoteDataSource);
+};
+
+
+sp<IDataSource> RemoteDataSource::wrap(const sp<DataSource> &source) {
+ return new RemoteDataSource(source);
+}
+RemoteDataSource::RemoteDataSource(const sp<DataSource> &source) {
+ mSource = source;
+ sp<MemoryDealer> memoryDealer = new MemoryDealer(kBufferSize, "RemoteDataSource");
+ mMemory = memoryDealer->allocate(kBufferSize);
+ if (mMemory == NULL) {
+ ALOGE("Failed to allocate memory!");
+ }
+}
+RemoteDataSource::~RemoteDataSource() {
+ close();
+}
+sp<IMemory> RemoteDataSource::getIMemory() {
+ return mMemory;
+}
+ssize_t RemoteDataSource::readAt(off64_t offset, size_t size) {
+ ALOGV("readAt(%" PRId64 ", %zu)", offset, size);
+ return mSource->readAt(offset, mMemory->pointer(), size);
+}
+status_t RemoteDataSource::getSize(off64_t* size) {
+ return mSource->getSize(size);
+}
+void RemoteDataSource::close() {
+ mSource = NULL;
+}
+
// static
-sp<MediaExtractor> MediaExtractor::Create(
+sp<IMediaExtractor> MediaExtractor::Create(
const sp<DataSource> &source, const char *mime) {
+ ALOGV("MediaExtractor::Create %s", mime);
+
+ char value[PROPERTY_VALUE_MAX];
+ if (property_get("media.stagefright.extractremote", value, NULL)
+ && (!strcmp("0", value) || !strcasecmp("false", value))) {
+ // local extractor
+ ALOGW("creating media extractor in calling process");
+ return CreateFromService(source, mime);
+ } else {
+ // remote extractor
+ ALOGV("get service manager");
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
+
+ // Check if it's WVM, since WVMExtractor needs to be created in the media server process,
+ // not the extractor process.
+ String8 mime8;
+ float confidence;
+ sp<AMessage> meta;
+ if (SniffWVM(source, &mime8, &confidence, &meta) &&
+ !strcasecmp(mime8, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+ return new WVMExtractor(source);
+ }
+
+ if (binder != 0) {
+ sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
+ sp<IMediaExtractor> ex = mediaExService->makeExtractor(RemoteDataSource::wrap(source), mime);
+ return ex;
+ } else {
+ ALOGE("extractor service not running");
+ return NULL;
+ }
+ }
+ return NULL;
+}
+
+sp<MediaExtractor> MediaExtractor::CreateFromService(
+ const sp<DataSource> &source, const char *mime) {
+
+ ALOGV("MediaExtractor::CreateFromService %s", mime);
+ DataSource::RegisterDefaultSniffers();
+
sp<AMessage> meta;
String8 tmp;
@@ -110,7 +224,7 @@
ret = new MatroskaExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
ret = new MPEG2TSExtractor(source);
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM) && getuid() == AID_MEDIA) {
// Return now. WVExtractor should not have the DrmFlag set in the block below.
return new WVMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
diff --git a/media/libstagefright/MediaSource.cpp b/media/libstagefright/MediaSource.cpp
index 576471a..a17757a 100644
--- a/media/libstagefright/MediaSource.cpp
+++ b/media/libstagefright/MediaSource.cpp
@@ -22,56 +22,4 @@
MediaSource::~MediaSource() {}
-////////////////////////////////////////////////////////////////////////////////
-
-MediaSource::ReadOptions::ReadOptions() {
- reset();
-}
-
-void MediaSource::ReadOptions::reset() {
- mOptions = 0;
- mSeekTimeUs = 0;
- mLatenessUs = 0;
- mNonBlocking = false;
-}
-
-void MediaSource::ReadOptions::setNonBlocking() {
- mNonBlocking = true;
-}
-
-void MediaSource::ReadOptions::clearNonBlocking() {
- mNonBlocking = false;
-}
-
-bool MediaSource::ReadOptions::getNonBlocking() const {
- return mNonBlocking;
-}
-
-void MediaSource::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
- mOptions |= kSeekTo_Option;
- mSeekTimeUs = time_us;
- mSeekMode = mode;
-}
-
-void MediaSource::ReadOptions::clearSeekTo() {
- mOptions &= ~kSeekTo_Option;
- mSeekTimeUs = 0;
- mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool MediaSource::ReadOptions::getSeekTo(
- int64_t *time_us, SeekMode *mode) const {
- *time_us = mSeekTimeUs;
- *mode = mSeekMode;
- return (mOptions & kSeekTo_Option) != 0;
-}
-
-void MediaSource::ReadOptions::setLateBy(int64_t lateness_us) {
- mLatenessUs = lateness_us;
-}
-
-int64_t MediaSource::ReadOptions::getLateBy() const {
- return mLatenessUs;
-}
-
} // namespace android
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 3a45e25..6f2d868 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -635,7 +635,7 @@
ALOGV("acquired buffer %#llx from input", (long long)bufferItem.mGraphicBuffer->getId());
- status = mInput->detachBuffer(bufferItem.mBuf);
+ status = mInput->detachBuffer(bufferItem.mSlot);
if (status != NO_ERROR) {
ALOGE("detaching buffer from input failed (%d)", status);
if (status == NO_INIT) {
@@ -677,7 +677,6 @@
bufferItem.mCrop,
static_cast<int32_t>(bufferItem.mScalingMode),
bufferItem.mTransform,
- bufferItem.mIsDroppable,
bufferItem.mFence);
// Attach and queue the buffer to the output.
diff --git a/media/libstagefright/MidiExtractor.cpp b/media/libstagefright/MidiExtractor.cpp
index f6b8c84..7525f57 100644
--- a/media/libstagefright/MidiExtractor.cpp
+++ b/media/libstagefright/MidiExtractor.cpp
@@ -281,7 +281,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> MidiExtractor::getTrack(size_t index)
+sp<IMediaSource> MidiExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index f24cf3a..67d9921 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -129,6 +129,9 @@
status_t NuMediaExtractor::setDataSource(int fd, off64_t offset, off64_t size) {
+ ALOGV("setDataSource fd=%d (%s), offset=%lld, length=%lld",
+ fd, nameForFd(fd).c_str(), (long long) offset, (long long) size);
+
Mutex::Autolock autoLock(mLock);
if (mImpl != NULL) {
@@ -186,6 +189,10 @@
for (size_t i = 0; i < mImpl->countTracks(); ++i) {
sp<MetaData> meta = mImpl->getTrackMetaData(i);
+ if (meta == NULL) {
+ ALOGW("no metadata for track %zu", i);
+ continue;
+ }
int32_t bitrate;
if (!meta->findInt32(kKeyBitRate, &bitrate)) {
@@ -278,7 +285,7 @@
}
}
- sp<MediaSource> source = mImpl->getTrack(index);
+ sp<IMediaSource> source = mImpl->getTrack(index);
CHECK_EQ((status_t)OK, source->start());
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 4c39194..41fbf75 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -70,7 +70,7 @@
const static uint32_t kMaxColorFormatSupported = 1000;
#define FACTORY_CREATE_ENCODER(name) \
-static sp<MediaSource> Make##name(const sp<MediaSource> &source, const sp<MetaData> &meta) { \
+static sp<IMediaSource> Make##name(const sp<IMediaSource> &source, const sp<MetaData> &meta) { \
return new name(source, meta); \
}
@@ -78,12 +78,12 @@
FACTORY_CREATE_ENCODER(AACEncoder)
-static sp<MediaSource> InstantiateSoftwareEncoder(
- const char *name, const sp<MediaSource> &source,
+static sp<IMediaSource> InstantiateSoftwareEncoder(
+ const char *name, const sp<IMediaSource> &source,
const sp<MetaData> &meta) {
struct FactoryInfo {
const char *name;
- sp<MediaSource> (*CreateFunc)(const sp<MediaSource> &, const sp<MetaData> &);
+ sp<IMediaSource> (*CreateFunc)(const sp<IMediaSource> &, const sp<MetaData> &);
};
static const FactoryInfo kFactoryInfo[] = {
@@ -289,10 +289,10 @@
}
// static
-sp<MediaSource> OMXCodec::Create(
+sp<IMediaSource> OMXCodec::Create(
const sp<IOMX> &omx,
const sp<MetaData> &meta, bool createEncoder,
- const sp<MediaSource> &source,
+ const sp<IMediaSource> &source,
const char *matchComponentName,
uint32_t flags,
const sp<ANativeWindow> &nativeWindow) {
@@ -337,7 +337,7 @@
}
if (createEncoder) {
- sp<MediaSource> softwareCodec =
+ sp<IMediaSource> softwareCodec =
InstantiateSoftwareEncoder(componentName, source, meta);
if (softwareCodec != NULL) {
@@ -1426,7 +1426,7 @@
bool isEncoder,
const char *mime,
const char *componentName,
- const sp<MediaSource> &source,
+ const sp<IMediaSource> &source,
const sp<ANativeWindow> &nativeWindow)
: mOMX(omx),
mOMXLivesLocally(omx->livesLocally(node, getpid())),
@@ -3535,8 +3535,21 @@
}
void OMXCodec::addCodecSpecificData(const void *data, size_t size) {
+
+ if (size > SIZE_MAX - (sizeof(CodecSpecificData) - 1)) {
+ // this would require the size to be ~4GB, which should be near impossible
+ // given that it is the size of an in-memory chunk of data
+ ALOGE("b/23540411");
+ return;
+ }
+
CodecSpecificData *specific =
- (CodecSpecificData *)malloc(sizeof(CodecSpecificData) + size - 1);
+ (CodecSpecificData *)malloc(sizeof(CodecSpecificData) - 1 + size);
+
+ if (specific == NULL) {
+ ALOGE("b/23540411");
+ return;
+ }
specific->mSize = size;
memcpy(specific->mData, data, size);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index d63ac96..9162f80 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -965,7 +965,7 @@
mMeta->setInt32(kKeyChannelCount, mChannelCount);
mMeta->setInt64(kKeyOpusSeekPreRoll /* ns */, kOpusSeekPreRollUs * 1000 /* = 80 ms*/);
mMeta->setInt64(kKeyOpusCodecDelay /* ns */,
- mCodecDelay /* sample/s */ * 1000000000 / kOpusSampleRate);
+ mCodecDelay /* sample/s */ * 1000000000ll / kOpusSampleRate);
return OK;
}
@@ -1265,17 +1265,17 @@
return;
}
- descLen = U32_AT(&flac[8 + typeLen]);
+ if (flacSize < 32 || flacSize - 32 < typeLen) {
+ return;
+ }
- if (flacSize < 32 ||
- flacSize - 32 < typeLen ||
- flacSize - 32 - typeLen < descLen) {
+ descLen = U32_AT(&flac[8 + typeLen]);
+ if (flacSize - 32 - typeLen < descLen) {
return;
}
dataLen = U32_AT(&flac[8 + typeLen + 4 + descLen + 16]);
-
// we've already checked above that (flacSize - 32 - typeLen - descLen) >= 0
if (flacSize - 32 - typeLen - descLen < dataLen) {
return;
@@ -1325,7 +1325,7 @@
return mInitCheck != OK ? 0 : 1;
}
-sp<MediaSource> OggExtractor::getTrack(size_t index) {
+sp<IMediaSource> OggExtractor::getTrack(size_t index) {
if (index >= 1) {
return NULL;
}
diff --git a/media/libstagefright/ProcessInfo.cpp b/media/libstagefright/ProcessInfo.cpp
index b4172b3..353f108 100644
--- a/media/libstagefright/ProcessInfo.cpp
+++ b/media/libstagefright/ProcessInfo.cpp
@@ -32,19 +32,23 @@
sp<IProcessInfoService> service = interface_cast<IProcessInfoService>(binder);
size_t length = 1;
- int32_t states;
- status_t err = service->getProcessStatesFromPids(length, &pid, &states);
+ int32_t state;
+ static const int32_t INVALID_ADJ = -10000;
+ static const int32_t NATIVE_ADJ = -1000;
+ int32_t score = INVALID_ADJ;
+ status_t err = service->getProcessStatesAndOomScoresFromPids(length, &pid, &state, &score);
if (err != OK) {
- ALOGE("getProcessStatesFromPids failed");
+ ALOGE("getProcessStatesAndOomScoresFromPids failed");
return false;
}
- ALOGV("pid %d states %d", pid, states);
- if (states < 0) {
+ ALOGV("pid %d state %d score %d", pid, state, score);
+ if (score <= NATIVE_ADJ) {
+ ALOGE("pid %d invalid OOM adjustments value %d", pid, score);
return false;
}
- // Use process state as the priority. Lower the value, higher the priority.
- *priority = states;
+ // Use OOM adjustments value as the priority. Lower the value, higher the priority.
+ *priority = score;
return true;
}
diff --git a/media/libstagefright/SampleIterator.cpp b/media/libstagefright/SampleIterator.cpp
index 032bbb9..7bf3437 100644
--- a/media/libstagefright/SampleIterator.cpp
+++ b/media/libstagefright/SampleIterator.cpp
@@ -84,6 +84,11 @@
CHECK(sampleIndex < mStopChunkSampleIndex);
+ if (mSamplesPerChunk == 0) {
+ ALOGE("b/22802344");
+ return ERROR_MALFORMED;
+ }
+
uint32_t chunk =
(sampleIndex - mFirstChunkSampleIndex) / mSamplesPerChunk
+ mFirstChunk;
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index 93cf055..39459e2 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -255,8 +255,11 @@
!= (ssize_t)sizeof(buffer)) {
return ERROR_IO;
}
-
- CHECK(U32_AT(buffer) >= 1); // chunk index is 1 based in the spec.
+ // chunk index is 1 based in the spec.
+ if (U32_AT(buffer) < 1) {
+ ALOGE("b/23534160");
+ return ERROR_OUT_OF_RANGE;
+ }
// We want the chunk index to be 0-based.
mSampleToChunkEntries[i].startChunk = U32_AT(buffer) - 1;
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index e37e909..055b659 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -139,7 +139,7 @@
static VideoFrame *extractVideoFrame(
const char *componentName,
const sp<MetaData> &trackMeta,
- const sp<MediaSource> &source,
+ const sp<IMediaSource> &source,
int64_t frameTimeUs,
int seekMode) {
@@ -147,6 +147,7 @@
sp<AMessage> videoFormat;
if (convertMetaDataToMessage(trackMeta, &videoFormat) != OK) {
+ ALOGE("b/23680780");
ALOGW("Failed to convert meta data to message");
return NULL;
}
@@ -458,7 +459,7 @@
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(
i, MediaExtractor::kIncludeExtensiveMetaData);
- sp<MediaSource> source = mExtractor->getTrack(i);
+ sp<IMediaSource> source = mExtractor->getTrack(i);
if (source.get() == NULL) {
ALOGV("unable to instantiate video track.");
@@ -661,9 +662,12 @@
}
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
const char *lang;
- trackMeta->findCString(kKeyMediaLanguage, &lang);
- timedTextLang.append(String8(lang));
- timedTextLang.append(String8(":"));
+ if (trackMeta->findCString(kKeyMediaLanguage, &lang)) {
+ timedTextLang.append(String8(lang));
+ timedTextLang.append(String8(":"));
+ } else {
+ ALOGE("No language found for timed text");
+ }
}
}
}
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index e8abf48..e4bf67a 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -308,9 +308,9 @@
// First time seeing the buffer? Added it to the SMS slot
if (item.mGraphicBuffer != NULL) {
- mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+ mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
}
- mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+ mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
// check for the timing of this buffer
if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) {
@@ -320,7 +320,7 @@
if (item.mTimestamp < mStartTimeNs) {
// This frame predates start of record, discard
mConsumer->releaseBuffer(
- item.mBuf, item.mFrameNumber, EGL_NO_DISPLAY,
+ item.mSlot, item.mFrameNumber, EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR, Fence::NO_FENCE);
continue;
}
@@ -346,13 +346,13 @@
return ERROR_END_OF_STREAM;
}
- mCurrentSlot = item.mBuf;
+ mCurrentSlot = item.mSlot;
// First time seeing the buffer? Added it to the SMS slot
if (item.mGraphicBuffer != NULL) {
- mSlots[item.mBuf].mGraphicBuffer = item.mGraphicBuffer;
+ mSlots[item.mSlot].mGraphicBuffer = item.mGraphicBuffer;
}
- mSlots[item.mBuf].mFrameNumber = item.mFrameNumber;
+ mSlots[item.mSlot].mFrameNumber = item.mFrameNumber;
mCurrentBuffers.push_back(mSlots[mCurrentSlot].mGraphicBuffer);
int64_t prevTimeStamp = mCurrentTimestamp;
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 17f0201..2a8b635 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "Utils"
#include <utils/Log.h>
#include <ctype.h>
+#include <stdio.h>
+#include <sys/stat.h>
#include "include/ESDS.h"
@@ -89,8 +91,14 @@
status_t convertMetaDataToMessage(
const sp<MetaData> &meta, sp<AMessage> *format) {
+
format->clear();
+ if (meta == NULL) {
+ ALOGE("convertMetaDataToMessage: NULL input");
+ return BAD_VALUE;
+ }
+
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
@@ -1007,5 +1015,37 @@
*sync = settings;
}
+AString nameForFd(int fd) {
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ AString result;
+ snprintf(buffer, SIZE, "/proc/%d/fd/%d", getpid(), fd);
+ struct stat s;
+ if (lstat(buffer, &s) == 0) {
+ if ((s.st_mode & S_IFMT) == S_IFLNK) {
+ char linkto[256];
+ int len = readlink(buffer, linkto, sizeof(linkto));
+ if(len > 0) {
+ if(len > 255) {
+ linkto[252] = '.';
+ linkto[253] = '.';
+ linkto[254] = '.';
+ linkto[255] = 0;
+ } else {
+ linkto[len] = 0;
+ }
+ result.append(linkto);
+ }
+ } else {
+ result.append("unexpected type for ");
+ result.append(buffer);
+ }
+ } else {
+ result.append("couldn't open ");
+ result.append(buffer);
+ }
+ return result;
+}
+
} // namespace android
diff --git a/media/libstagefright/VBRISeeker.cpp b/media/libstagefright/VBRISeeker.cpp
index 8a0fcac..58f2c60 100644
--- a/media/libstagefright/VBRISeeker.cpp
+++ b/media/libstagefright/VBRISeeker.cpp
@@ -149,7 +149,7 @@
}
bool VBRISeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
- if (mDurationUs < 0) {
+ if (mDurationUs < 0 || mSegments.size() == 0) {
return false;
}
diff --git a/media/libstagefright/WAVExtractor.cpp b/media/libstagefright/WAVExtractor.cpp
index 811929b..680c0c6 100644
--- a/media/libstagefright/WAVExtractor.cpp
+++ b/media/libstagefright/WAVExtractor.cpp
@@ -116,7 +116,7 @@
return mInitCheck == OK ? 1 : 0;
}
-sp<MediaSource> WAVExtractor::getTrack(size_t index) {
+sp<IMediaSource> WAVExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index > 0) {
return NULL;
}
diff --git a/media/libstagefright/WVMExtractor.cpp b/media/libstagefright/WVMExtractor.cpp
index bc48272..d1b2f54 100644
--- a/media/libstagefright/WVMExtractor.cpp
+++ b/media/libstagefright/WVMExtractor.cpp
@@ -95,7 +95,7 @@
return (mImpl != NULL) ? mImpl->countTracks() : 0;
}
-sp<MediaSource> WVMExtractor::getTrack(size_t index) {
+sp<IMediaSource> WVMExtractor::getTrack(size_t index) {
if (mImpl == NULL) {
return NULL;
}
diff --git a/media/libstagefright/codecs/aacenc/AACEncoder.cpp b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
index bebb9dc..9e596ff 100644
--- a/media/libstagefright/codecs/aacenc/AACEncoder.cpp
+++ b/media/libstagefright/codecs/aacenc/AACEncoder.cpp
@@ -30,7 +30,7 @@
namespace android {
-AACEncoder::AACEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta)
+AACEncoder::AACEncoder(const sp<IMediaSource> &source, const sp<MetaData> &meta)
: mSource(source),
mMeta(meta),
mStarted(false),
diff --git a/media/libstagefright/codecs/amrnb/common/Android.mk b/media/libstagefright/codecs/amrnb/common/Android.mk
index 3e4c8c7..15220a4 100644
--- a/media/libstagefright/codecs/amrnb/common/Android.mk
+++ b/media/libstagefright/codecs/amrnb/common/Android.mk
@@ -69,7 +69,8 @@
LOCAL_CFLAGS += -Werror
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow unsigned-integer-overflow
LOCAL_MODULE := libstagefright_amrnb_common
diff --git a/media/libstagefright/codecs/amrnb/dec/Android.mk b/media/libstagefright/codecs/amrnb/dec/Android.mk
index b966762..7967ec3 100644
--- a/media/libstagefright/codecs/amrnb/dec/Android.mk
+++ b/media/libstagefright/codecs/amrnb/dec/Android.mk
@@ -49,7 +49,7 @@
LOCAL_CFLAGS += -Werror
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_amrnbdec
@@ -74,7 +74,7 @@
LOCAL_CFLAGS += -Werror
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_STATIC_LIBRARIES := \
libstagefright_amrnbdec libstagefright_amrwbdec
@@ -105,7 +105,7 @@
libstagefright_amrnb_common libaudioutils liblog
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_amrnbdec_test
LOCAL_MODULE_TAGS := optional
diff --git a/media/libstagefright/codecs/amrnb/enc/Android.mk b/media/libstagefright/codecs/amrnb/enc/Android.mk
index 9216124..f8a41af 100644
--- a/media/libstagefright/codecs/amrnb/enc/Android.mk
+++ b/media/libstagefright/codecs/amrnb/enc/Android.mk
@@ -71,7 +71,8 @@
LOCAL_CFLAGS += -Werror
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_amrnbenc
@@ -94,7 +95,8 @@
LOCAL_CFLAGS += -Werror
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_STATIC_LIBRARIES := \
libstagefright_amrnbenc
@@ -126,7 +128,8 @@
libstagefright_amrnb_common
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+#addressing b/25409744
+#LOCAL_SANITIZE := signed-integer-overflow
LOCAL_MODULE := libstagefright_amrnbenc_test
LOCAL_MODULE_TAGS := tests
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index cd6c3b1..7fafb6f 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -209,6 +209,8 @@
mEOSStatus == INPUT_EOS_SEEN) {
return;
}
+ // Continue as outQueue may be empty now.
+ continue;
}
BufferInfo *inInfo = *inQueue.begin();
@@ -220,15 +222,23 @@
EOSseen = true;
}
- if (inHeader->nFilledLen > 0 &&
- vpx_codec_decode((vpx_codec_ctx_t *)mCtx,
- inHeader->pBuffer + inHeader->nOffset,
- inHeader->nFilledLen,
- &mTimeStamps[mTimeStampIdx], 0)) {
- ALOGE("on2 decoder failed to decode frame.");
- notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
- return;
+ if (inHeader->nFilledLen > 0) {
+ vpx_codec_err_t err = vpx_codec_decode(
+ (vpx_codec_ctx_t *)mCtx, inHeader->pBuffer + inHeader->nOffset,
+ inHeader->nFilledLen, &mTimeStamps[mTimeStampIdx], 0);
+ if (err == VPX_CODEC_OK) {
+ inInfo->mOwnedByUs = false;
+ inQueue.erase(inQueue.begin());
+ inInfo = NULL;
+ notifyEmptyBufferDone(inHeader);
+ inHeader = NULL;
+ } else {
+ ALOGE("on2 decoder failed to decode frame.");
+ notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
+ return;
+ }
}
+
mTimeStampIdx = (mTimeStampIdx + 1) % kNumBuffers;
if (!outputBuffers(
@@ -240,12 +250,6 @@
if (portWillReset) {
return;
}
-
- inInfo->mOwnedByUs = false;
- inQueue.erase(inQueue.begin());
- inInfo = NULL;
- notifyEmptyBufferDone(inHeader);
- inHeader = NULL;
}
}
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 410f9d0..0f28e8d 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -106,24 +106,24 @@
status_t SoftVPXEncoder::initEncoder() {
vpx_codec_err_t codec_return;
+ status_t result = UNKNOWN_ERROR;
- mCodecContext = new vpx_codec_ctx_t;
- mCodecConfiguration = new vpx_codec_enc_cfg_t;
mCodecInterface = vpx_codec_vp8_cx();
-
if (mCodecInterface == NULL) {
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
ALOGD("VP8: initEncoder. BRMode: %u. TSLayers: %zu. KF: %u. QP: %u - %u",
(uint32_t)mBitrateControlMode, mTemporalLayers, mKeyFrameInterval,
mMinQuantizer, mMaxQuantizer);
+
+ mCodecConfiguration = new vpx_codec_enc_cfg_t;
codec_return = vpx_codec_enc_config_default(mCodecInterface,
mCodecConfiguration,
0); // Codec specific flags
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error populating default configuration for vpx encoder.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
mCodecConfiguration->g_w = mWidth;
@@ -250,7 +250,7 @@
default:
{
ALOGE("Wrong number of temporal layers %zu", mTemporalLayers);
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
}
@@ -272,6 +272,7 @@
mCodecConfiguration->rc_max_quantizer = mMaxQuantizer;
}
+ mCodecContext = new vpx_codec_ctx_t;
codec_return = vpx_codec_enc_init(mCodecContext,
mCodecInterface,
mCodecConfiguration,
@@ -279,7 +280,7 @@
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error initializing vpx encoder");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
codec_return = vpx_codec_control(mCodecContext,
@@ -287,7 +288,7 @@
mDCTPartitions);
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error setting dct partitions for vpx encoder.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
// Extra CBR settings
@@ -313,7 +314,7 @@
}
if (codec_return != VPX_CODEC_OK) {
ALOGE("Error setting cbr parameters for vpx encoder.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
}
@@ -321,16 +322,20 @@
free(mConversionBuffer);
mConversionBuffer = NULL;
if (((uint64_t)mWidth * mHeight) > ((uint64_t)INT32_MAX / 3)) {
- ALOGE("b/25812794, Buffer size is too big.");
- return UNKNOWN_ERROR;
+ ALOGE("b/25812794, Buffer size is too big, width=%d, height=%d.", mWidth, mHeight);
+ goto CLEAN_UP;
}
mConversionBuffer = (uint8_t *)malloc(mWidth * mHeight * 3 / 2);
if (mConversionBuffer == NULL) {
ALOGE("Allocating conversion buffer failed.");
- return UNKNOWN_ERROR;
+ goto CLEAN_UP;
}
}
return OK;
+
+CLEAN_UP:
+ releaseEncoder();
+ return result;
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index c559682..fd8bf2b 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -56,6 +56,7 @@
mNumFramesLeftOnPage(-1),
mSawInputEos(false),
mSignalledOutputEos(false),
+ mSignalledError(false),
mOutputPortSettingsChange(NONE) {
initPorts();
CHECK_EQ(initDecoder(), (status_t)OK);
@@ -247,7 +248,7 @@
List<BufferInfo *> &inQueue = getPortQueue(0);
List<BufferInfo *> &outQueue = getPortQueue(1);
- if (mOutputPortSettingsChange != NONE) {
+ if (mSignalledError || mOutputPortSettingsChange != NONE) {
return;
}
@@ -271,9 +272,19 @@
mVi = new vorbis_info;
vorbis_info_init(mVi);
- CHECK_EQ(0, _vorbis_unpack_info(mVi, &bits));
+ int ret = _vorbis_unpack_info(mVi, &bits);
+ if (ret != 0) {
+ notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+ mSignalledError = true;
+ return;
+ }
} else {
- CHECK_EQ(0, _vorbis_unpack_books(mVi, &bits));
+ int ret = _vorbis_unpack_books(mVi, &bits);
+ if (ret != 0) {
+ notify(OMX_EventError, OMX_ErrorUndefined, ret, NULL);
+ mSignalledError = true;
+ return;
+ }
CHECK(mState == NULL);
mState = new vorbis_dsp_state;
@@ -439,6 +450,7 @@
mSawInputEos = false;
mSignalledOutputEos = false;
+ mSignalledError = false;
mOutputPortSettingsChange = NONE;
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
index 1d00816..30d137b 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.h
@@ -61,6 +61,7 @@
int32_t mNumFramesLeftOnPage;
bool mSawInputEos;
bool mSignalledOutputEos;
+ bool mSignalledError;
enum {
NONE,
diff --git a/media/libstagefright/filters/GraphicBufferListener.cpp b/media/libstagefright/filters/GraphicBufferListener.cpp
index a606315..c1aaa17 100644
--- a/media/libstagefright/filters/GraphicBufferListener.cpp
+++ b/media/libstagefright/filters/GraphicBufferListener.cpp
@@ -101,11 +101,11 @@
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
// shouldn't happen, since we track num frames available
ALOGE("frame was not available");
- item.mBuf = -1;
+ item.mSlot = -1;
return item;
} else if (err != OK) {
ALOGE("acquireBuffer returned err=%d", err);
- item.mBuf = -1;
+ item.mSlot = -1;
return item;
}
@@ -119,8 +119,8 @@
// If this is the first time we're seeing this buffer, add it to our
// slot table.
if (item.mGraphicBuffer != NULL) {
- ALOGV("setting mBufferSlot %d", item.mBuf);
- mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+ ALOGV("setting mBufferSlot %d", item.mSlot);
+ mBufferSlot[item.mSlot] = item.mGraphicBuffer;
}
return item;
@@ -128,24 +128,24 @@
sp<GraphicBuffer> GraphicBufferListener::getBuffer(BufferItem item) {
sp<GraphicBuffer> buf;
- if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+ if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+ ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
return buf;
}
- buf = mBufferSlot[item.mBuf];
+ buf = mBufferSlot[item.mSlot];
CHECK(buf.get() != NULL);
return buf;
}
status_t GraphicBufferListener::releaseBuffer(BufferItem item) {
- if (item.mBuf < 0 || item.mBuf >= BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("getBuffer() received invalid BufferItem: mBuf==%d", item.mBuf);
+ if (item.mSlot < 0 || item.mSlot >= BufferQueue::NUM_BUFFER_SLOTS) {
+ ALOGE("getBuffer() received invalid BufferItem: mSlot==%d", item.mSlot);
return ERROR_OUT_OF_RANGE;
}
- mConsumer->releaseBuffer(item.mBuf, item.mFrameNumber,
+ mConsumer->releaseBuffer(item.mSlot, item.mFrameNumber,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
return OK;
diff --git a/media/libstagefright/filters/MediaFilter.cpp b/media/libstagefright/filters/MediaFilter.cpp
index 0cf6b06..cd69418 100644
--- a/media/libstagefright/filters/MediaFilter.cpp
+++ b/media/libstagefright/filters/MediaFilter.cpp
@@ -773,7 +773,7 @@
convertRGBAToARGB(
(uint8_t*)bufPtr, buf->getWidth(), buf->getHeight(),
buf->getStride(), inputInfo->mData->data());
- inputInfo->mBufferID = item.mBuf;
+ inputInfo->mBufferID = item.mSlot;
inputInfo->mGeneration = mGeneration;
inputInfo->mOutputFlags = 0;
inputInfo->mStatus = BufferInfo::OWNED_BY_US;
diff --git a/media/libstagefright/foundation/Android.mk b/media/libstagefright/foundation/Android.mk
index 6c70e98..e17534f 100644
--- a/media/libstagefright/foundation/Android.mk
+++ b/media/libstagefright/foundation/Android.mk
@@ -15,6 +15,8 @@
AString.cpp \
AStringUtils.cpp \
AWakeLock.cpp \
+ MediaBuffer.cpp \
+ MetaData.cpp \
ParsedMessage.cpp \
base64.cpp \
hexdump.cpp
@@ -32,6 +34,7 @@
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
+
LOCAL_MODULE:= libstagefright_foundation
diff --git a/media/libstagefright/MediaBuffer.cpp b/media/libstagefright/foundation/MediaBuffer.cpp
similarity index 85%
rename from media/libstagefright/MediaBuffer.cpp
rename to media/libstagefright/foundation/MediaBuffer.cpp
index 1f80a47..d83a351 100644
--- a/media/libstagefright/MediaBuffer.cpp
+++ b/media/libstagefright/foundation/MediaBuffer.cpp
@@ -30,6 +30,9 @@
namespace android {
+// allocations larger than this will use shared memory
+static const size_t kSharedMemThreshold = 64 * 1024;
+
MediaBuffer::MediaBuffer(void *data, size_t size)
: mObserver(NULL),
mNextBuffer(NULL),
@@ -47,13 +50,29 @@
: mObserver(NULL),
mNextBuffer(NULL),
mRefCount(0),
- mData(malloc(size)),
+ mData(NULL),
mSize(size),
mRangeOffset(0),
mRangeLength(size),
mOwnsData(true),
mMetaData(new MetaData),
mOriginal(NULL) {
+ if (size < kSharedMemThreshold) {
+ mData = malloc(size);
+ } else {
+ sp<MemoryDealer> memoryDealer = new MemoryDealer(size, "MediaBuffer");
+ mMemory = memoryDealer->allocate(size);
+ if (mMemory == NULL) {
+ ALOGW("Failed to allocate shared memory, trying regular allocation!");
+ mData = malloc(size);
+ if (mData == NULL) {
+ ALOGE("Out of memory");
+ }
+ } else {
+ mData = mMemory->pointer();
+ ALOGV("Allocated shared mem buffer of size %zu @ %p", size, mData);
+ }
+ }
}
MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
@@ -158,7 +177,7 @@
MediaBuffer::~MediaBuffer() {
CHECK(mObserver == NULL);
- if (mOwnsData && mData != NULL) {
+ if (mOwnsData && mData != NULL && mMemory == NULL) {
free(mData);
mData = NULL;
}
diff --git a/media/libstagefright/MetaData.cpp b/media/libstagefright/foundation/MetaData.cpp
similarity index 84%
rename from media/libstagefright/MetaData.cpp
rename to media/libstagefright/foundation/MetaData.cpp
index 1a11c1e..b847eed 100644
--- a/media/libstagefright/MetaData.cpp
+++ b/media/libstagefright/foundation/MetaData.cpp
@@ -107,7 +107,7 @@
}
bool MetaData::findInt32(uint32_t key, int32_t *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_INT32) {
@@ -122,7 +122,7 @@
}
bool MetaData::findInt64(uint32_t key, int64_t *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_INT64) {
@@ -137,7 +137,7 @@
}
bool MetaData::findFloat(uint32_t key, float *value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_FLOAT) {
@@ -152,7 +152,7 @@
}
bool MetaData::findPointer(uint32_t key, void **value) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_POINTER) {
@@ -170,7 +170,7 @@
uint32_t key,
int32_t *left, int32_t *top,
int32_t *right, int32_t *bottom) {
- uint32_t type;
+ uint32_t type = 0;
const void *data;
size_t size;
if (!findData(key, &type, &data, &size) || type != TYPE_RECT) {
@@ -377,5 +377,57 @@
}
}
+status_t MetaData::writeToParcel(Parcel &parcel) {
+ size_t numItems = mItems.size();
+ parcel.writeUint32(uint32_t(numItems));
+ for (size_t i = 0; i < numItems; i++) {
+ int32_t key = mItems.keyAt(i);
+ const typed_data &item = mItems.valueAt(i);
+ uint32_t type;
+ const void *data;
+ size_t size;
+ item.getData(&type, &data, &size);
+ parcel.writeInt32(key);
+ parcel.writeUint32(type);
+ parcel.writeByteArray(size, (uint8_t*)data);
+ }
+ return OK;
+}
+
+status_t MetaData::updateFromParcel(const Parcel &parcel) {
+ uint32_t numItems;
+ if (parcel.readUint32(&numItems) == OK) {
+
+ for (size_t i = 0; i < numItems; i++) {
+ int32_t key;
+ uint32_t type;
+ uint32_t size;
+ status_t ret = parcel.readInt32(&key);
+ ret |= parcel.readUint32(&type);
+ ret |= parcel.readUint32(&size);
+ if (ret != OK) {
+ break;
+ }
+ // copy data directly from Parcel storage, then advance position
+ setData(key, type, parcel.readInplace(size), size);
+ }
+
+ return OK;
+ }
+ ALOGW("no metadata in parcel");
+ return UNKNOWN_ERROR;
+}
+
+
+/* static */
+sp<MetaData> MetaData::createFromParcel(const Parcel &parcel) {
+
+ sp<MetaData> meta = new MetaData();
+ meta->updateFromParcel(parcel);
+ return meta;
+}
+
+
+
} // namespace android
diff --git a/media/libstagefright/httplive/HTTPDownloader.cpp b/media/libstagefright/httplive/HTTPDownloader.cpp
index dff6b0b..861b85a 100644
--- a/media/libstagefright/httplive/HTTPDownloader.cpp
+++ b/media/libstagefright/httplive/HTTPDownloader.cpp
@@ -31,6 +31,7 @@
#include <openssl/aes.h>
#include <openssl/md5.h>
#include <utils/Mutex.h>
+#include <inttypes.h>
namespace android {
@@ -165,7 +166,10 @@
size_t maxBytesToRead = bufferRemaining;
if (range_length >= 0) {
int64_t bytesLeftInRange = range_length - buffer->size();
- if (bytesLeftInRange < (int64_t)maxBytesToRead) {
+ if (bytesLeftInRange < 0) {
+ ALOGE("range_length %" PRId64 " wrapped around", range_length);
+ return ERROR_OUT_OF_RANGE;
+ } else if (bytesLeftInRange < (int64_t)maxBytesToRead) {
maxBytesToRead = bytesLeftInRange;
if (bytesLeftInRange == 0) {
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 1557401..cebf95c 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -477,7 +477,7 @@
sp<MetaData> meta = packetSource->getFormat();
if (meta == NULL) {
- return -EAGAIN;
+ return -EWOULDBLOCK;
}
if (stream == STREAMTYPE_AUDIO) {
diff --git a/media/libstagefright/include/AACEncoder.h b/media/libstagefright/include/AACEncoder.h
index 52beb0e..462e905 100644
--- a/media/libstagefright/include/AACEncoder.h
+++ b/media/libstagefright/include/AACEncoder.h
@@ -27,9 +27,9 @@
class MediaBufferGroup;
-class AACEncoder: public MediaSource {
+class AACEncoder: public BnMediaSource {
public:
- AACEncoder(const sp<MediaSource> &source, const sp<MetaData> &meta);
+ AACEncoder(const sp<IMediaSource> &source, const sp<MetaData> &meta);
virtual status_t start(MetaData *params);
virtual status_t stop();
@@ -42,7 +42,7 @@
virtual ~AACEncoder();
private:
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<MetaData> mMeta;
bool mStarted;
MediaBufferGroup *mBufferGroup;
diff --git a/media/libstagefright/include/AACExtractor.h b/media/libstagefright/include/AACExtractor.h
index e98ca82..e231e62 100644
--- a/media/libstagefright/include/AACExtractor.h
+++ b/media/libstagefright/include/AACExtractor.h
@@ -32,7 +32,7 @@
AACExtractor(const sp<DataSource> &source, const sp<AMessage> &meta);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/AMRExtractor.h b/media/libstagefright/include/AMRExtractor.h
index 4a1c827..0770397 100644
--- a/media/libstagefright/include/AMRExtractor.h
+++ b/media/libstagefright/include/AMRExtractor.h
@@ -32,7 +32,7 @@
AMRExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 758b2c9..1204ee8 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -23,6 +23,7 @@
#include <media/AudioResamplerPublic.h>
#include <media/MediaPlayerInterface.h>
+#include <media/IMediaExtractor.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/TimeSource.h>
@@ -36,8 +37,6 @@
struct ClockEstimator;
class IDataSource;
class MediaBuffer;
-struct MediaExtractor;
-struct MediaSource;
struct NuCachedSource2;
class IGraphicBufferProducer;
@@ -170,8 +169,8 @@
sp<DataSource> mFileSource;
- sp<MediaSource> mVideoTrack;
- sp<MediaSource> mVideoSource;
+ sp<IMediaSource> mVideoTrack;
+ sp<IMediaSource> mVideoSource;
sp<AwesomeRenderer> mVideoRenderer;
bool mVideoRenderingStarted;
bool mVideoRendererIsPreview;
@@ -179,9 +178,9 @@
int32_t mStartGeneration;
ssize_t mActiveAudioTrackIndex;
- sp<MediaSource> mAudioTrack;
- sp<MediaSource> mOmxSource;
- sp<MediaSource> mAudioSource;
+ sp<IMediaSource> mAudioTrack;
+ sp<IMediaSource> mOmxSource;
+ sp<IMediaSource> mAudioSource;
AudioPlayer *mAudioPlayer;
AudioPlaybackRate mPlaybackSettings;
int64_t mDurationUs;
@@ -250,9 +249,10 @@
int64_t mLastVideoTimeUs;
TimedTextDriver *mTextDriver;
+ int32_t mSelectedTimedTextTrack;
sp<WVMExtractor> mWVMExtractor;
- sp<MediaExtractor> mExtractor;
+ sp<IMediaExtractor> mExtractor;
status_t setDataSource_l(
const sp<IMediaHTTPService> &httpService,
@@ -260,7 +260,7 @@
const KeyedVector<String8, String8> *headers = NULL);
status_t setDataSource_l(const sp<DataSource> &dataSource);
- status_t setDataSource_l(const sp<MediaExtractor> &extractor);
+ status_t setDataSource_l(const sp<IMediaExtractor> &extractor);
void reset_l();
status_t seekTo_l(int64_t timeUs);
status_t pause_l(bool at_eos = false);
@@ -270,14 +270,14 @@
void cancelPlayerEvents(bool keepNotifications = false);
- void setAudioSource(sp<MediaSource> source);
+ void setAudioSource(sp<IMediaSource> source);
status_t initAudioDecoder();
- void setVideoSource(sp<MediaSource> source);
+ void setVideoSource(sp<IMediaSource> source);
status_t initVideoDecoder(uint32_t flags = 0);
- void addTextSource_l(size_t trackIndex, const sp<MediaSource>& source);
+ void addTextSource_l(size_t trackIndex, const sp<IMediaSource>& source);
void onStreamDone();
@@ -359,7 +359,7 @@
status_t setVideoScalingMode_l(int32_t mode);
status_t getTrackInfo(Parcel* reply) const;
- status_t selectAudioTrack_l(const sp<MediaSource>& source, size_t trackIndex);
+ status_t selectAudioTrack_l(const sp<IMediaSource>& source, size_t trackIndex);
// when select is true, the given track is selected.
// otherwise, the given track is unselected.
diff --git a/media/libstagefright/include/DRMExtractor.h b/media/libstagefright/include/DRMExtractor.h
index b4e4afb..a035d8c 100644
--- a/media/libstagefright/include/DRMExtractor.h
+++ b/media/libstagefright/include/DRMExtractor.h
@@ -18,6 +18,7 @@
#define DRM_EXTRACTOR_H_
+#include <media/IMediaSource.h>
#include <media/stagefright/MediaExtractor.h>
#include <drm/DrmManagerClient.h>
@@ -34,7 +35,7 @@
DRMExtractor(const sp<DataSource> &source, const char *mime);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
@@ -44,7 +45,7 @@
private:
sp<DataSource> mDataSource;
- sp<MediaExtractor> mOriginalExtractor;
+ sp<IMediaExtractor> mOriginalExtractor;
sp<DecryptHandle> mDecryptHandle;
DrmManagerClient* mDrmManagerClient;
diff --git a/media/libstagefright/include/FLACExtractor.h b/media/libstagefright/include/FLACExtractor.h
index ded91c2..a6e6c1d 100644
--- a/media/libstagefright/include/FLACExtractor.h
+++ b/media/libstagefright/include/FLACExtractor.h
@@ -32,7 +32,7 @@
FLACExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MP3Extractor.h b/media/libstagefright/include/MP3Extractor.h
index c83d9e8..2fd04f2 100644
--- a/media/libstagefright/include/MP3Extractor.h
+++ b/media/libstagefright/include/MP3Extractor.h
@@ -34,10 +34,11 @@
MP3Extractor(const sp<DataSource> &source, const sp<AMessage> &meta);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
+ virtual const char * name() { return "MP3Extractor"; }
private:
status_t mInitCheck;
diff --git a/media/libstagefright/include/MPEG2PSExtractor.h b/media/libstagefright/include/MPEG2PSExtractor.h
index 22cb02d..e815f0e 100644
--- a/media/libstagefright/include/MPEG2PSExtractor.h
+++ b/media/libstagefright/include/MPEG2PSExtractor.h
@@ -34,7 +34,7 @@
MPEG2PSExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MPEG2TSExtractor.h b/media/libstagefright/include/MPEG2TSExtractor.h
index 8eb8f6c..9907572 100644
--- a/media/libstagefright/include/MPEG2TSExtractor.h
+++ b/media/libstagefright/include/MPEG2TSExtractor.h
@@ -38,7 +38,7 @@
MPEG2TSExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MPEG4Extractor.h b/media/libstagefright/include/MPEG4Extractor.h
index 3067c3d..cff976d 100644
--- a/media/libstagefright/include/MPEG4Extractor.h
+++ b/media/libstagefright/include/MPEG4Extractor.h
@@ -53,7 +53,7 @@
MPEG4Extractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/MidiExtractor.h b/media/libstagefright/include/MidiExtractor.h
index 9a2abc0..333277b 100644
--- a/media/libstagefright/include/MidiExtractor.h
+++ b/media/libstagefright/include/MidiExtractor.h
@@ -56,7 +56,7 @@
MidiExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
diff --git a/media/libstagefright/include/OggExtractor.h b/media/libstagefright/include/OggExtractor.h
index c647cbb..592c264 100644
--- a/media/libstagefright/include/OggExtractor.h
+++ b/media/libstagefright/include/OggExtractor.h
@@ -34,10 +34,11 @@
OggExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
+ virtual const char * name() { return "OggExtractor"; }
protected:
virtual ~OggExtractor();
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index fd739d0..6684e1f 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -18,6 +18,7 @@
#define STAGEFRIGHT_METADATA_RETRIEVER_H_
+#include <media/IMediaExtractor.h>
#include <media/MediaMetadataRetrieverInterface.h>
#include <media/stagefright/OMXClient.h>
@@ -47,7 +48,7 @@
private:
OMXClient mClient;
sp<DataSource> mSource;
- sp<MediaExtractor> mExtractor;
+ sp<IMediaExtractor> mExtractor;
bool mParsedMetaData;
KeyedVector<int, String8> mMetaData;
diff --git a/media/libstagefright/include/WAVExtractor.h b/media/libstagefright/include/WAVExtractor.h
index c567ccd..91ee870 100644
--- a/media/libstagefright/include/WAVExtractor.h
+++ b/media/libstagefright/include/WAVExtractor.h
@@ -33,10 +33,11 @@
WAVExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
+ virtual const char * name() { return "WAVExtractor"; }
protected:
virtual ~WAVExtractor();
diff --git a/media/libstagefright/include/WVMExtractor.h b/media/libstagefright/include/WVMExtractor.h
index ab7e8b8..5b91072 100644
--- a/media/libstagefright/include/WVMExtractor.h
+++ b/media/libstagefright/include/WVMExtractor.h
@@ -46,7 +46,7 @@
WVMExtractor(const sp<DataSource> &source);
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(size_t index, uint32_t flags);
virtual sp<MetaData> getMetaData();
virtual void setUID(uid_t uid);
diff --git a/media/libstagefright/matroska/Android.mk b/media/libstagefright/matroska/Android.mk
index 1e8c2b2..193408c 100644
--- a/media/libstagefright/matroska/Android.mk
+++ b/media/libstagefright/matroska/Android.mk
@@ -10,6 +10,7 @@
LOCAL_CFLAGS += -Wno-multichar -Werror -Wall
LOCAL_CLANG := true
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_MODULE:= libstagefright_matroska
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 09e6b9b..82b471f 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -772,7 +772,7 @@
return mTracks.size();
}
-sp<MediaSource> MatroskaExtractor::getTrack(size_t index) {
+sp<IMediaSource> MatroskaExtractor::getTrack(size_t index) {
if (index >= mTracks.size()) {
return NULL;
}
diff --git a/media/libstagefright/matroska/MatroskaExtractor.h b/media/libstagefright/matroska/MatroskaExtractor.h
index db36bf8..120ef82 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.h
+++ b/media/libstagefright/matroska/MatroskaExtractor.h
@@ -37,7 +37,7 @@
virtual size_t countTracks();
- virtual sp<MediaSource> getTrack(size_t index);
+ virtual sp<IMediaSource> getTrack(size_t index);
virtual sp<MetaData> getTrackMetaData(
size_t index, uint32_t flags);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index bec99a5..2790a0e 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -524,15 +524,10 @@
}
sp<MediaSource> ATSParser::Program::getSource(SourceType type) {
- size_t index = (type == AUDIO) ? 0 : 0;
-
for (size_t i = 0; i < mStreams.size(); ++i) {
sp<MediaSource> source = mStreams.editValueAt(i)->getSource(type);
if (source != NULL) {
- if (index == 0) {
- return source;
- }
- --index;
+ return source;
}
}
@@ -546,6 +541,8 @@
return true;
} else if (type == VIDEO && stream->isVideo()) {
return true;
+ } else if (type == META && stream->isMeta()) {
+ return true;
}
}
@@ -1499,23 +1496,38 @@
}
sp<MediaSource> ATSParser::getSource(SourceType type) {
- int which = -1; // any
-
+ sp<MediaSource> firstSourceFound;
for (size_t i = 0; i < mPrograms.size(); ++i) {
const sp<Program> &program = mPrograms.editItemAt(i);
-
- if (which >= 0 && (int)program->number() != which) {
+ sp<MediaSource> source = program->getSource(type);
+ if (source == NULL) {
continue;
}
+ if (firstSourceFound == NULL) {
+ firstSourceFound = source;
+ }
+ // Prefer programs with both audio/video
+ switch (type) {
+ case VIDEO: {
+ if (program->hasSource(AUDIO)) {
+ return source;
+ }
+ break;
+ }
- sp<MediaSource> source = program->getSource(type);
+ case AUDIO: {
+ if (program->hasSource(VIDEO)) {
+ return source;
+ }
+ break;
+ }
- if (source != NULL) {
- return source;
+ default:
+ return source;
}
}
- return NULL;
+ return firstSourceFound;
}
bool ATSParser::hasSource(SourceType type) const {
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 36ec367..c967463 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -1121,6 +1121,10 @@
if (mFormat != NULL && currentStartCode == 0xb8) {
// GOP layer
+ if (offset + 7 >= size) {
+ ALOGE("Size too small");
+ return NULL;
+ }
gopFound = true;
isClosedGop = (data[offset + 7] & 0x40) != 0;
brokenLink = (data[offset + 7] & 0x20) != 0;
diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
index 0f18fac..078a5f0 100644
--- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp
@@ -125,7 +125,7 @@
return mTracks.size();
}
-sp<MediaSource> MPEG2PSExtractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG2PSExtractor::getTrack(size_t index) {
if (index >= mTracks.size()) {
return NULL;
}
diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
index cbe9673..0b456c3 100644
--- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
+++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp
@@ -120,7 +120,7 @@
return mSourceImpls.size();
}
-sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) {
+sp<IMediaSource> MPEG2TSExtractor::getTrack(size_t index) {
if (index >= mSourceImpls.size()) {
return NULL;
}
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 1a7dc9d..acdc4b0 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -64,19 +64,19 @@
return;
}
- err = consumer->detachBuffer(bi.mBuf);
+ err = consumer->detachBuffer(bi.mSlot);
if (err != OK) {
ALOGE("PersistentProxyListener: detachBuffer failed (%d)", err);
return;
}
- err = consumer->attachBuffer(&bi.mBuf, bi.mGraphicBuffer);
+ err = consumer->attachBuffer(&bi.mSlot, bi.mGraphicBuffer);
if (err != OK) {
ALOGE("PersistentProxyListener: attachBuffer failed (%d)", err);
return;
}
- err = consumer->releaseBuffer(bi.mBuf, 0,
+ err = consumer->releaseBuffer(bi.mSlot, 0,
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, bi.mFence);
if (err != OK) {
ALOGE("PersistentProxyListener: releaseBuffer failed (%d)", err);
@@ -382,7 +382,7 @@
// Find matching entry in our cached copy of the BufferQueue slots.
// If we find a match, release that slot. If we don't, the BufferQueue
// has dropped that GraphicBuffer, and there's nothing for us to release.
- int id = codecBuffer.mBuf;
+ int id = codecBuffer.mSlot;
sp<Fence> fence = new Fence(fenceFd);
if (mBufferSlot[id] != NULL &&
mBufferSlot[id]->handle == codecBuffer.mGraphicBuffer->handle) {
@@ -476,7 +476,7 @@
++mNumBufferAcquired;
--mNumFramesAvailable;
- releaseBuffer(item.mBuf, item.mFrameNumber,
+ releaseBuffer(item.mSlot, item.mFrameNumber,
item.mGraphicBuffer, item.mFence);
}
return;
@@ -530,8 +530,8 @@
// If this is the first time we're seeing this buffer, add it to our
// slot table.
if (item.mGraphicBuffer != NULL) {
- ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
- mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+ ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mSlot);
+ mBufferSlot[item.mSlot] = item.mGraphicBuffer;
}
err = UNKNOWN_ERROR;
@@ -557,10 +557,10 @@
}
if (err != OK) {
- ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
- releaseBuffer(item.mBuf, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
+ ALOGV("submitBuffer_l failed, releasing bq slot %d", item.mSlot);
+ releaseBuffer(item.mSlot, item.mFrameNumber, item.mGraphicBuffer, item.mFence);
} else {
- ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
+ ALOGV("buffer submitted (bq %d, cbi %d)", item.mSlot, cbi);
setLatestBuffer_l(item, dropped);
}
@@ -600,7 +600,7 @@
}
BufferItem item;
- item.mBuf = mLatestBufferId;
+ item.mSlot = mLatestBufferId;
item.mFrameNumber = mLatestBufferFrameNum;
item.mTimestamp = mRepeatLastFrameTimestamp;
item.mFence = mLatestBufferFence;
@@ -642,7 +642,7 @@
}
}
- mLatestBufferId = item.mBuf;
+ mLatestBufferId = item.mSlot;
mLatestBufferFrameNum = item.mFrameNumber;
mRepeatLastFrameTimestamp = item.mTimestamp + mRepeatAfterUs * 1000;
@@ -754,8 +754,8 @@
}
CodecBuffer& codecBuffer(mCodecBuffers.editItemAt(cbi));
- codecBuffer.mGraphicBuffer = mBufferSlot[item.mBuf];
- codecBuffer.mBuf = item.mBuf;
+ codecBuffer.mGraphicBuffer = mBufferSlot[item.mSlot];
+ codecBuffer.mSlot = item.mSlot;
codecBuffer.mFrameNumber = item.mFrameNumber;
OMX_BUFFERHEADERTYPE* header = codecBuffer.mHeader;
@@ -880,11 +880,11 @@
// If this is the first time we're seeing this buffer, add it to our
// slot table.
if (item.mGraphicBuffer != NULL) {
- ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mBuf);
- mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+ ALOGV("onFrameAvailable: setting mBufferSlot %d", item.mSlot);
+ mBufferSlot[item.mSlot] = item.mGraphicBuffer;
}
- releaseBuffer(item.mBuf, item.mFrameNumber,
+ releaseBuffer(item.mSlot, item.mFrameNumber,
item.mGraphicBuffer, item.mFence);
}
return;
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 2f929d9..7150684 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -195,7 +195,7 @@
uint64_t mFrameNumber;
// buffer producer's buffer slot for buffer
- int mBuf;
+ int mSlot;
sp<GraphicBuffer> mGraphicBuffer;
};
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 7f357c9..539b4e3 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -266,6 +266,10 @@
status_t OMX::freeNode(node_id node) {
OMXNodeInstance *instance = findInstance(node);
+ if (instance == NULL) {
+ return OK;
+ }
+
{
Mutex::Autolock autoLock(mLock);
ssize_t index = mLiveNodes.indexOfKey(IInterface::asBinder(instance->observer()));
@@ -293,14 +297,26 @@
status_t OMX::sendCommand(
node_id node, OMX_COMMANDTYPE cmd, OMX_S32 param) {
- return findInstance(node)->sendCommand(cmd, param);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->sendCommand(cmd, param);
}
status_t OMX::getParameter(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
ALOGV("getParameter(%u %#x %p %zd)", node, index, params, size);
- return findInstance(node)->getParameter(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getParameter(
index, params, size);
}
@@ -308,84 +324,162 @@
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
ALOGV("setParameter(%u %#x %p %zd)", node, index, params, size);
- return findInstance(node)->setParameter(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setParameter(
index, params, size);
}
status_t OMX::getConfig(
node_id node, OMX_INDEXTYPE index,
void *params, size_t size) {
- return findInstance(node)->getConfig(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getConfig(
index, params, size);
}
status_t OMX::setConfig(
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) {
- return findInstance(node)->setConfig(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setConfig(
index, params, size);
}
status_t OMX::getState(
node_id node, OMX_STATETYPE* state) {
- return findInstance(node)->getState(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getState(
state);
}
status_t OMX::enableGraphicBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable) {
- return findInstance(node)->enableGraphicBuffers(port_index, enable);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->enableGraphicBuffers(port_index, enable);
}
status_t OMX::getGraphicBufferUsage(
node_id node, OMX_U32 port_index, OMX_U32* usage) {
- return findInstance(node)->getGraphicBufferUsage(port_index, usage);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getGraphicBufferUsage(port_index, usage);
}
status_t OMX::storeMetaDataInBuffers(
node_id node, OMX_U32 port_index, OMX_BOOL enable, MetadataBufferType *type) {
- return findInstance(node)->storeMetaDataInBuffers(port_index, enable, type);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->storeMetaDataInBuffers(port_index, enable, type);
}
status_t OMX::prepareForAdaptivePlayback(
node_id node, OMX_U32 portIndex, OMX_BOOL enable,
OMX_U32 maxFrameWidth, OMX_U32 maxFrameHeight) {
- return findInstance(node)->prepareForAdaptivePlayback(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->prepareForAdaptivePlayback(
portIndex, enable, maxFrameWidth, maxFrameHeight);
}
status_t OMX::configureVideoTunnelMode(
node_id node, OMX_U32 portIndex, OMX_BOOL tunneled,
OMX_U32 audioHwSync, native_handle_t **sidebandHandle) {
- return findInstance(node)->configureVideoTunnelMode(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->configureVideoTunnelMode(
portIndex, tunneled, audioHwSync, sidebandHandle);
}
status_t OMX::useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer, OMX_U32 allottedSize) {
- return findInstance(node)->useBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->useBuffer(
port_index, params, buffer, allottedSize);
}
status_t OMX::useGraphicBuffer(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
- return findInstance(node)->useGraphicBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->useGraphicBuffer(
port_index, graphicBuffer, buffer);
}
status_t OMX::updateGraphicBufferInMeta(
node_id node, OMX_U32 port_index,
const sp<GraphicBuffer> &graphicBuffer, buffer_id buffer) {
- return findInstance(node)->updateGraphicBufferInMeta(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->updateGraphicBufferInMeta(
port_index, graphicBuffer, buffer);
}
status_t OMX::createInputSurface(
node_id node, OMX_U32 port_index,
sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
- return findInstance(node)->createInputSurface(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->createInputSurface(
port_index, bufferProducer, type);
}
@@ -399,35 +493,71 @@
status_t OMX::setInputSurface(
node_id node, OMX_U32 port_index,
const sp<IGraphicBufferConsumer> &bufferConsumer, MetadataBufferType *type) {
- return findInstance(node)->setInputSurface(port_index, bufferConsumer, type);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setInputSurface(port_index, bufferConsumer, type);
}
status_t OMX::signalEndOfInputStream(node_id node) {
- return findInstance(node)->signalEndOfInputStream();
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->signalEndOfInputStream();
}
status_t OMX::allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data) {
- return findInstance(node)->allocateBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->allocateBuffer(
port_index, size, buffer, buffer_data);
}
status_t OMX::allocateBufferWithBackup(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer, OMX_U32 allottedSize) {
- return findInstance(node)->allocateBufferWithBackup(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->allocateBufferWithBackup(
port_index, params, buffer, allottedSize);
}
status_t OMX::freeBuffer(node_id node, OMX_U32 port_index, buffer_id buffer) {
- return findInstance(node)->freeBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->freeBuffer(
port_index, buffer);
}
status_t OMX::fillBuffer(node_id node, buffer_id buffer, int fenceFd) {
- return findInstance(node)->fillBuffer(buffer, fenceFd);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->fillBuffer(buffer, fenceFd);
}
status_t OMX::emptyBuffer(
@@ -435,7 +565,13 @@
buffer_id buffer,
OMX_U32 range_offset, OMX_U32 range_length,
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
- return findInstance(node)->emptyBuffer(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->emptyBuffer(
buffer, range_offset, range_length, flags, timestamp, fenceFd);
}
@@ -443,7 +579,13 @@
node_id node,
const char *parameter_name,
OMX_INDEXTYPE *index) {
- return findInstance(node)->getExtensionIndex(
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->getExtensionIndex(
parameter_name, index);
}
@@ -453,7 +595,13 @@
InternalOptionType type,
const void *data,
size_t size) {
- return findInstance(node)->setInternalOption(port_index, type, data, size);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return NAME_NOT_FOUND;
+ }
+
+ return instance->setInternalOption(port_index, type, data, size);
}
OMX_ERRORTYPE OMX::OnEvent(
@@ -463,9 +611,14 @@
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData) {
ALOGV("OnEvent(%d, %" PRIu32", %" PRIu32 ")", eEvent, nData1, nData2);
+ OMXNodeInstance *instance = findInstance(node);
+
+ if (instance == NULL) {
+ return OMX_ErrorComponentNotFound;
+ }
// Forward to OMXNodeInstance.
- findInstance(node)->onEvent(eEvent, nData1, nData2);
+ instance->onEvent(eEvent, nData1, nData2);
sp<OMX::CallbackDispatcher> dispatcher = findDispatcher(node);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index a1485f0..9ae238a 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -655,6 +655,11 @@
status_t OMXNodeInstance::useBuffer(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer, OMX_U32 allottedSize) {
+ if (params == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
if (allottedSize > params->size()) {
return BAD_VALUE;
@@ -699,6 +704,10 @@
status_t OMXNodeInstance::useGraphicBuffer2_l(
OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
OMX::buffer_id *buffer) {
+ if (graphicBuffer == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
// port definition
OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -751,6 +760,10 @@
status_t OMXNodeInstance::useGraphicBuffer(
OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
OMX::buffer_id *buffer) {
+ if (graphicBuffer == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
Mutex::Autolock autoLock(mLock);
// See if the newer version of the extension is present.
@@ -811,6 +824,12 @@
status_t OMXNodeInstance::updateGraphicBufferInMeta_l(
OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
OMX::buffer_id buffer, OMX_BUFFERHEADERTYPE *header) {
+ // No need to check |graphicBuffer| since NULL is valid for it as below.
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
if (portIndex != kPortIndexInput && portIndex != kPortIndexOutput) {
return BAD_VALUE;
}
@@ -911,6 +930,11 @@
status_t OMXNodeInstance::createInputSurface(
OMX_U32 portIndex, sp<IGraphicBufferProducer> *bufferProducer, MetadataBufferType *type) {
+ if (bufferProducer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autolock(mLock);
status_t err = createGraphicBufferSource(portIndex, NULL /* bufferConsumer */, type);
@@ -926,6 +950,10 @@
status_t OMXNodeInstance::createPersistentInputSurface(
sp<IGraphicBufferProducer> *bufferProducer,
sp<IGraphicBufferConsumer> *bufferConsumer) {
+ if (bufferProducer == NULL || bufferConsumer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
String8 name("GraphicBufferSource");
sp<IGraphicBufferProducer> producer;
@@ -971,6 +999,11 @@
status_t OMXNodeInstance::allocateBuffer(
OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
void **buffer_data) {
+ if (buffer == NULL || buffer_data == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
BufferMeta *buffer_meta = new BufferMeta(size);
@@ -1009,6 +1042,11 @@
status_t OMXNodeInstance::allocateBufferWithBackup(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer, OMX_U32 allottedSize) {
+ if (params == NULL || buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
if (allottedSize > params->size()) {
return BAD_VALUE;
@@ -1056,6 +1094,10 @@
removeActiveBuffer(portIndex, buffer);
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
BufferMeta *buffer_meta = static_cast<BufferMeta *>(header->pAppPrivate);
OMX_ERRORTYPE err = OMX_FreeBuffer(mHandle, portIndex, header);
@@ -1072,6 +1114,10 @@
Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
header->nFilledLen = 0;
header->nOffset = 0;
header->nFlags = 0;
@@ -1105,6 +1151,10 @@
Mutex::Autolock autoLock(mLock);
OMX_BUFFERHEADERTYPE *header = findBufferHeader(buffer);
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
BufferMeta *buffer_meta =
static_cast<BufferMeta *>(header->pAppPrivate);
sp<ABuffer> backup = buffer_meta->getBuffer(header, true /* backup */, false /* limit */);
@@ -1256,6 +1306,11 @@
status_t OMXNodeInstance::emptyGraphicBuffer(
OMX_BUFFERHEADERTYPE *header, const sp<GraphicBuffer> &graphicBuffer,
OMX_U32 flags, OMX_TICKS timestamp, int fenceFd) {
+ if (header == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
+
Mutex::Autolock autoLock(mLock);
OMX::buffer_id buffer = findBufferID(header);
status_t err = updateGraphicBufferInMeta_l(kPortIndexInput, graphicBuffer, buffer, header);
@@ -1385,6 +1440,10 @@
if (msg.type == omx_message::FILL_BUFFER_DONE) {
OMX_BUFFERHEADERTYPE *buffer =
findBufferHeader(msg.u.extended_buffer_data.buffer);
+ if (buffer == NULL) {
+ ALOGE("b/25884056");
+ return BAD_VALUE;
+ }
{
Mutex::Autolock _l(mDebugLock);
@@ -1523,6 +1582,10 @@
OMX_IN OMX_U32 nData1,
OMX_IN OMX_U32 nData2,
OMX_IN OMX_PTR pEventData) {
+ if (pAppData == NULL) {
+ ALOGE("b/25884056");
+ return OMX_ErrorBadParameter;
+ }
OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
if (instance->mDying) {
return OMX_ErrorNone;
@@ -1536,6 +1599,10 @@
OMX_IN OMX_HANDLETYPE /* hComponent */,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ if (pAppData == NULL) {
+ ALOGE("b/25884056");
+ return OMX_ErrorBadParameter;
+ }
OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
if (instance->mDying) {
return OMX_ErrorNone;
@@ -1550,6 +1617,10 @@
OMX_IN OMX_HANDLETYPE /* hComponent */,
OMX_IN OMX_PTR pAppData,
OMX_IN OMX_BUFFERHEADERTYPE* pBuffer) {
+ if (pAppData == NULL) {
+ ALOGE("b/25884056");
+ return OMX_ErrorBadParameter;
+ }
OMXNodeInstance *instance = static_cast<OMXNodeInstance *>(pAppData);
if (instance->mDying) {
return OMX_ErrorNone;
@@ -1590,7 +1661,7 @@
void OMXNodeInstance::freeActiveBuffers() {
// Make sure to count down here, as freeBuffer will in turn remove
// the active buffer from the vector...
- for (size_t i = mActiveBuffers.size(); i;) {
+ for (size_t i = mActiveBuffers.size(); i > 0;) {
i--;
freeBuffer(mActiveBuffers[i].mPortIndex, mActiveBuffers[i].mID);
}
diff --git a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
index 4ce165b..e1f4125 100644
--- a/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoDecoderOMXComponent.cpp
@@ -388,6 +388,14 @@
uint32_t oldHeight = def->format.video.nFrameHeight;
uint32_t newWidth = video_def->nFrameWidth;
uint32_t newHeight = video_def->nFrameHeight;
+ // We need width, height, stride and slice-height to be non-zero and sensible.
+ // These values were chosen to prevent integer overflows further down the line, and do
+ // not indicate support for 32kx32k video.
+ if (newWidth > 32768 || newHeight > 32768
+ || video_def->nStride > 32768 || video_def->nSliceHeight > 32768) {
+ ALOGE("b/22885421");
+ return OMX_ErrorBadParameter;
+ }
if (newWidth != oldWidth || newHeight != oldHeight) {
bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
if (outputPort) {
diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
index a770f49..72823e2 100644
--- a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
+++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp
@@ -23,7 +23,6 @@
#include "include/SoftVideoEncoderOMXComponent.h"
-#include <hardware/gralloc.h>
#include <media/hardware/HardwareAPI.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -71,7 +70,6 @@
mBitrate(192000),
mFramerate(30 << 16), // Q16 format
mColorFormat(OMX_COLOR_FormatYUV420Planar),
- mGrallocModule(NULL),
mMinOutputBufferSize(384), // arbitrary, using one uncompressed macroblock
mMinCompressionRatio(1), // max output size is normally the input size
mComponentRole(componentRole),
@@ -500,13 +498,6 @@
return NULL;
}
- if (mGrallocModule == NULL) {
- CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule));
- }
-
- const gralloc_module_t *grmodule =
- (const gralloc_module_t *)mGrallocModule;
-
buffer_handle_t handle;
int format;
size_t srcStride;
@@ -564,19 +555,21 @@
return NULL;
}
+ auto& mapper = GraphicBufferMapper::get();
+
void *bits = NULL;
struct android_ycbcr ycbcr;
status_t res;
if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
- res = grmodule->lock_ycbcr(
- grmodule, handle,
+ res = mapper.lockYCbCr(
+ handle,
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
- 0, 0, width, height, &ycbcr);
+ Rect(width, height), &ycbcr);
} else {
- res = grmodule->lock(
- grmodule, handle,
+ res = mapper.lock(
+ handle,
GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER,
- 0, 0, width, height, &bits);
+ Rect(width, height), &bits);
}
if (res != OK) {
ALOGE("Unable to lock image buffer %p for access", handle);
@@ -620,7 +613,7 @@
break;
}
- if (grmodule->unlock(grmodule, handle) != OK) {
+ if (mapper.unlock(handle) != OK) {
ALOGE("Unable to unlock image buffer %p for access", handle);
}
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 644b6ed..5159de3 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -244,7 +244,7 @@
NodeReaper &operator=(const NodeReaper &);
};
-static sp<MediaExtractor> CreateExtractorFromURI(const char *uri) {
+static sp<IMediaExtractor> CreateExtractorFromURI(const char *uri) {
sp<DataSource> source =
DataSource::CreateFromURI(NULL /* httpService */, uri);
@@ -492,14 +492,14 @@
return NULL;
}
-static sp<MediaSource> CreateSourceForMime(const char *mime) {
+static sp<IMediaSource> CreateSourceForMime(const char *mime) {
const char *url = GetURLForMime(mime);
if (url == NULL) {
return NULL;
}
- sp<MediaExtractor> extractor = CreateExtractorFromURI(url);
+ sp<IMediaExtractor> extractor = CreateExtractorFromURI(url);
if (extractor == NULL) {
return NULL;
@@ -559,7 +559,7 @@
return OK;
}
- sp<MediaSource> source = CreateSourceForMime(mime);
+ sp<IMediaSource> source = CreateSourceForMime(mime);
if (source == NULL) {
printf(" * Unable to open test content for type '%s', "
@@ -569,14 +569,14 @@
return OK;
}
- sp<MediaSource> seekSource = CreateSourceForMime(mime);
+ sp<IMediaSource> seekSource = CreateSourceForMime(mime);
if (source == NULL || seekSource == NULL) {
return UNKNOWN_ERROR;
}
CHECK_EQ(seekSource->start(), (status_t)OK);
- sp<MediaSource> codec = OMXCodec::Create(
+ sp<IMediaSource> codec = OMXCodec::Create(
mOMX, source->getFormat(), false /* createEncoder */,
source, componentName);
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index d7c3bd6..576a0a4 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -116,8 +116,15 @@
// to the highest sequence number (extended to 32 bits) received so far.
uint32_t seq1 = seqNum | (mHighestSeqNumber & 0xffff0000);
- uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) + 0x10000);
- uint32_t seq3 = seqNum | ((mHighestSeqNumber & 0xffff0000) - 0x10000);
+
+ // non-overflowing version of:
+ // uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) + 0x10000);
+ uint32_t seq2 = seqNum | (((mHighestSeqNumber >> 16) + 1) << 16);
+
+ // non-underflowing version of:
+ // uint32_t seq2 = seqNum | ((mHighestSeqNumber & 0xffff0000) - 0x10000);
+ uint32_t seq3 = seqNum | ((((mHighestSeqNumber >> 16) | 0x10000) - 1) << 16);
+
uint32_t diff1 = AbsDiff(seq1, mHighestSeqNumber);
uint32_t diff2 = AbsDiff(seq2, mHighestSeqNumber);
uint32_t diff3 = AbsDiff(seq3, mHighestSeqNumber);
diff --git a/media/libstagefright/rtsp/ARTPWriter.cpp b/media/libstagefright/rtsp/ARTPWriter.cpp
index 56c4aa6..1f6b6f7 100644
--- a/media/libstagefright/rtsp/ARTPWriter.cpp
+++ b/media/libstagefright/rtsp/ARTPWriter.cpp
@@ -104,7 +104,7 @@
mFd = -1;
}
-status_t ARTPWriter::addSource(const sp<MediaSource> &source) {
+status_t ARTPWriter::addSource(const sp<IMediaSource> &source) {
mSource = source;
return OK;
}
diff --git a/media/libstagefright/rtsp/ARTPWriter.h b/media/libstagefright/rtsp/ARTPWriter.h
index be8bc13..62abd0a 100644
--- a/media/libstagefright/rtsp/ARTPWriter.h
+++ b/media/libstagefright/rtsp/ARTPWriter.h
@@ -37,7 +37,7 @@
struct ARTPWriter : public MediaWriter {
ARTPWriter(int fd);
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual bool reachedEOS();
virtual status_t start(MetaData *params);
virtual status_t stop();
@@ -72,7 +72,7 @@
int mRTCPFd;
#endif
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<ALooper> mLooper;
sp<AHandlerReflector<ARTPWriter> > mReflector;
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index a6f38bb..dfb3d9c 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -33,7 +33,7 @@
LOCAL_CFLAGS += -Werror -Wall
LOCAL_CLANG := true
-LOCAL_SANITIZE := signed-integer-overflow
+LOCAL_SANITIZE := unsigned-integer-overflow signed-integer-overflow
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.cpp b/media/libstagefright/timedtext/TimedText3GPPSource.cpp
index 4854121..0c8fb79 100644
--- a/media/libstagefright/timedtext/TimedText3GPPSource.cpp
+++ b/media/libstagefright/timedtext/TimedText3GPPSource.cpp
@@ -31,7 +31,7 @@
namespace android {
-TimedText3GPPSource::TimedText3GPPSource(const sp<MediaSource>& mediaSource)
+TimedText3GPPSource::TimedText3GPPSource(const sp<IMediaSource>& mediaSource)
: mSource(mediaSource) {
}
diff --git a/media/libstagefright/timedtext/TimedText3GPPSource.h b/media/libstagefright/timedtext/TimedText3GPPSource.h
index 4170940..fdc79ca 100644
--- a/media/libstagefright/timedtext/TimedText3GPPSource.h
+++ b/media/libstagefright/timedtext/TimedText3GPPSource.h
@@ -29,7 +29,7 @@
class TimedText3GPPSource : public TimedTextSource {
public:
- TimedText3GPPSource(const sp<MediaSource>& mediaSource);
+ TimedText3GPPSource(const sp<IMediaSource>& mediaSource);
virtual status_t start() { return mSource->start(); }
virtual status_t stop() { return mSource->stop(); }
virtual status_t read(
@@ -44,7 +44,7 @@
virtual ~TimedText3GPPSource();
private:
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
status_t extractAndAppendLocalDescriptions(
int64_t timeUs, const MediaBuffer *textBuffer, Parcel *parcel);
diff --git a/media/libstagefright/timedtext/TimedTextDriver.cpp b/media/libstagefright/timedtext/TimedTextDriver.cpp
index 55a9803..fd0eebb 100644
--- a/media/libstagefright/timedtext/TimedTextDriver.cpp
+++ b/media/libstagefright/timedtext/TimedTextDriver.cpp
@@ -188,7 +188,7 @@
}
status_t TimedTextDriver::addInBandTextSource(
- size_t trackIndex, const sp<MediaSource>& mediaSource) {
+ size_t trackIndex, const sp<IMediaSource>& mediaSource) {
sp<TimedTextSource> source =
TimedTextSource::CreateTimedTextSource(mediaSource);
if (source == NULL) {
diff --git a/media/libstagefright/timedtext/TimedTextSource.cpp b/media/libstagefright/timedtext/TimedTextSource.cpp
index 953f7b5..e5aa382 100644
--- a/media/libstagefright/timedtext/TimedTextSource.cpp
+++ b/media/libstagefright/timedtext/TimedTextSource.cpp
@@ -33,7 +33,7 @@
// static
sp<TimedTextSource> TimedTextSource::CreateTimedTextSource(
- const sp<MediaSource>& mediaSource) {
+ const sp<IMediaSource>& mediaSource) {
const char *mime;
CHECK(mediaSource->getFormat()->findCString(kKeyMIMEType, &mime));
if (strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP) == 0) {
diff --git a/media/libstagefright/timedtext/TimedTextSource.h b/media/libstagefright/timedtext/TimedTextSource.h
index 8c1c1cd..9946721 100644
--- a/media/libstagefright/timedtext/TimedTextSource.h
+++ b/media/libstagefright/timedtext/TimedTextSource.h
@@ -35,7 +35,7 @@
OUT_OF_BAND_FILE_SMI = 2,
};
static sp<TimedTextSource> CreateTimedTextSource(
- const sp<MediaSource>& source);
+ const sp<IMediaSource>& source);
static sp<TimedTextSource> CreateTimedTextSource(
const sp<DataSource>& source, FileType filetype);
TimedTextSource() {}
diff --git a/media/libstagefright/webm/WebmFrameThread.cpp b/media/libstagefright/webm/WebmFrameThread.cpp
index a4b8a42..7eb4745 100644
--- a/media/libstagefright/webm/WebmFrameThread.cpp
+++ b/media/libstagefright/webm/WebmFrameThread.cpp
@@ -246,7 +246,7 @@
}
WebmFrameMediaSourceThread::WebmFrameMediaSourceThread(
- const sp<MediaSource>& source,
+ const sp<IMediaSource>& source,
int type,
LinkedBlockingQueue<const sp<WebmFrame> >& sink,
uint64_t timeCodeScale,
diff --git a/media/libstagefright/webm/WebmFrameThread.h b/media/libstagefright/webm/WebmFrameThread.h
index d65d9b7..528984f 100644
--- a/media/libstagefright/webm/WebmFrameThread.h
+++ b/media/libstagefright/webm/WebmFrameThread.h
@@ -123,7 +123,7 @@
class WebmFrameMediaSourceThread: public WebmFrameSourceThread {
public:
WebmFrameMediaSourceThread(
- const sp<MediaSource>& source,
+ const sp<IMediaSource>& source,
int type,
LinkedBlockingQueue<const sp<WebmFrame> >& sink,
uint64_t timeCodeScale,
@@ -142,7 +142,7 @@
}
private:
- const sp<MediaSource> mSource;
+ const sp<IMediaSource> mSource;
const uint64_t mTimeCodeScale;
uint64_t mStartTimeUs;
diff --git a/media/libstagefright/webm/WebmWriter.cpp b/media/libstagefright/webm/WebmWriter.cpp
index 737f144..7f6ba01 100644
--- a/media/libstagefright/webm/WebmWriter.cpp
+++ b/media/libstagefright/webm/WebmWriter.cpp
@@ -328,7 +328,7 @@
return err;
}
-status_t WebmWriter::addSource(const sp<MediaSource> &source) {
+status_t WebmWriter::addSource(const sp<IMediaSource> &source) {
Mutex::Autolock l(mLock);
if (mStarted) {
ALOGE("Attempt to add source AFTER recording is started");
diff --git a/media/libstagefright/webm/WebmWriter.h b/media/libstagefright/webm/WebmWriter.h
index 4ad770e..4a7f506 100644
--- a/media/libstagefright/webm/WebmWriter.h
+++ b/media/libstagefright/webm/WebmWriter.h
@@ -40,7 +40,7 @@
~WebmWriter() { reset(); }
- virtual status_t addSource(const sp<MediaSource> &source);
+ virtual status_t addSource(const sp<IMediaSource> &source);
virtual status_t start(MetaData *param = NULL);
virtual status_t stop();
virtual status_t pause();
@@ -85,7 +85,7 @@
const char *mName;
sp<WebmElement> (*mMakeTrack)(const sp<MetaData>&);
- sp<MediaSource> mSource;
+ sp<IMediaSource> mSource;
sp<WebmElement> mTrackEntry;
sp<WebmFrameSourceThread> mThread;
LinkedBlockingQueue<const sp<WebmFrame> > mSink;
diff --git a/media/mediaserver/Android.mk b/media/mediaserver/Android.mk
index 580d8c1..ee99a26 100644
--- a/media/mediaserver/Android.mk
+++ b/media/mediaserver/Android.mk
@@ -14,22 +14,15 @@
main_mediaserver.cpp
LOCAL_SHARED_LIBRARIES := \
- libaudioflinger \
- libaudiopolicyservice \
libcamera_metadata\
libcameraservice \
- libicuuc \
libmedialogservice \
libresourcemanagerservice \
libcutils \
- libnbaio \
libmedia \
libmediaplayerservice \
libutils \
- liblog \
libbinder \
- libsoundtriggerservice \
- libradioservice
LOCAL_STATIC_LIBRARIES := \
libicuandroid_utils \
@@ -37,18 +30,8 @@
LOCAL_C_INCLUDES := \
frameworks/av/media/libmediaplayerservice \
- frameworks/av/services/medialog \
- frameworks/av/services/audioflinger \
- frameworks/av/services/audiopolicy \
- frameworks/av/services/audiopolicy/common/managerdefinitions/include \
- frameworks/av/services/audiopolicy/common/include \
- frameworks/av/services/audiopolicy/engine/interface \
frameworks/av/services/camera/libcameraservice \
frameworks/av/services/mediaresourcemanager \
- $(call include-path-for, audio-utils) \
- frameworks/av/services/soundtrigger \
- frameworks/av/services/radio \
- external/sonic
LOCAL_MODULE:= mediaserver
LOCAL_32_BIT_ONLY := true
diff --git a/media/mediaserver/main_mediaserver.cpp b/media/mediaserver/main_mediaserver.cpp
index 315aff4..7e3041b 100644
--- a/media/mediaserver/main_mediaserver.cpp
+++ b/media/mediaserver/main_mediaserver.cpp
@@ -18,130 +18,30 @@
#define LOG_TAG "mediaserver"
//#define LOG_NDEBUG 0
-#include <fcntl.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
#include <binder/IPCThreadState.h>
#include <binder/ProcessState.h>
#include <binder/IServiceManager.h>
-#include <cutils/properties.h>
#include <utils/Log.h>
#include "RegisterExtensions.h"
// from LOCAL_C_INCLUDES
-#include "AudioFlinger.h"
#include "CameraService.h"
-#include "IcuUtils.h"
-#include "MediaLogService.h"
#include "MediaPlayerService.h"
#include "ResourceManagerService.h"
-#include "service/AudioPolicyService.h"
-#include "SoundTriggerHwService.h"
-#include "RadioService.h"
using namespace android;
-int main(int argc __unused, char** argv)
+int main(int argc __unused, char **argv __unused)
{
signal(SIGPIPE, SIG_IGN);
- char value[PROPERTY_VALUE_MAX];
- bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
- pid_t childPid;
- // FIXME The advantage of making the process containing media.log service the parent process of
- // the process that contains all the other real services, is that it allows us to collect more
- // detailed information such as signal numbers, stop and continue, resource usage, etc.
- // But it is also more complex. Consider replacing this by independent processes, and using
- // binder on death notification instead.
- if (doLog && (childPid = fork()) != 0) {
- // media.log service
- //prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
- // unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
- strcpy(argv[0], "media.log");
- sp<ProcessState> proc(ProcessState::self());
- MediaLogService::instantiate();
- ProcessState::self()->startThreadPool();
- for (;;) {
- siginfo_t info;
- int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
- if (ret == EINTR) {
- continue;
- }
- if (ret < 0) {
- break;
- }
- char buffer[32];
- const char *code;
- switch (info.si_code) {
- case CLD_EXITED:
- code = "CLD_EXITED";
- break;
- case CLD_KILLED:
- code = "CLD_KILLED";
- break;
- case CLD_DUMPED:
- code = "CLD_DUMPED";
- break;
- case CLD_STOPPED:
- code = "CLD_STOPPED";
- break;
- case CLD_TRAPPED:
- code = "CLD_TRAPPED";
- break;
- case CLD_CONTINUED:
- code = "CLD_CONTINUED";
- break;
- default:
- snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
- code = buffer;
- break;
- }
- struct rusage usage;
- getrusage(RUSAGE_CHILDREN, &usage);
- ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
- info.si_pid, info.si_status, code,
- usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
- usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.log"));
- if (binder != 0) {
- Vector<String16> args;
- binder->dump(-1, args);
- }
- switch (info.si_code) {
- case CLD_EXITED:
- case CLD_KILLED:
- case CLD_DUMPED: {
- ALOG(LOG_INFO, "media.log", "exiting");
- _exit(0);
- // not reached
- }
- default:
- break;
- }
- }
- } else {
- // all other services
- if (doLog) {
- prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
- setpgid(0, 0); // but if I die first, don't kill my parent
- }
-#ifndef __BRILLO__
- // Brillo is headless and very resource constrained. As such, it doesn't
- // need an internationalization library for now.
- InitializeIcuOrDie();
-#endif
- sp<ProcessState> proc(ProcessState::self());
- sp<IServiceManager> sm = defaultServiceManager();
- ALOGI("ServiceManager: %p", sm.get());
- AudioFlinger::instantiate();
- MediaPlayerService::instantiate();
- ResourceManagerService::instantiate();
- CameraService::instantiate();
- AudioPolicyService::instantiate();
- SoundTriggerHwService::instantiate();
- RadioService::instantiate();
- registerExtensions();
- ProcessState::self()->startThreadPool();
- IPCThreadState::self()->joinThreadPool();
- }
+
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm(defaultServiceManager());
+ ALOGI("ServiceManager: %p", sm.get());
+ MediaPlayerService::instantiate();
+ ResourceManagerService::instantiate();
+ CameraService::instantiate();
+ registerExtensions();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
}
diff --git a/media/mtp/MtpDataPacket.cpp b/media/mtp/MtpDataPacket.cpp
index 052b700..d0ec2a6 100644
--- a/media/mtp/MtpDataPacket.cpp
+++ b/media/mtp/MtpDataPacket.cpp
@@ -25,8 +25,6 @@
#include "MtpDataPacket.h"
#include "MtpStringBuffer.h"
-#define MTP_BUFFER_SIZE 16384
-
namespace android {
MtpDataPacket::MtpDataPacket()
@@ -525,16 +523,9 @@
int MtpDataPacket::write(struct usb_request *request) {
MtpPacket::putUInt32(MTP_CONTAINER_LENGTH_OFFSET, mPacketSize);
MtpPacket::putUInt16(MTP_CONTAINER_TYPE_OFFSET, MTP_CONTAINER_TYPE_DATA);
-
- // send header separately from data
request->buffer = mBuffer;
- request->buffer_length = MTP_CONTAINER_HEADER_SIZE;
+ request->buffer_length = mPacketSize;
int ret = transfer(request);
- if (ret == MTP_CONTAINER_HEADER_SIZE) {
- request->buffer = mBuffer + MTP_CONTAINER_HEADER_SIZE;
- request->buffer_length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
- ret = transfer(request);
- }
return (ret < 0 ? ret : 0);
}
@@ -547,17 +538,17 @@
#endif // MTP_HOST
-void* MtpDataPacket::getData(int& outLength) const {
+void* MtpDataPacket::getData(int* outLength) const {
int length = mPacketSize - MTP_CONTAINER_HEADER_SIZE;
if (length > 0) {
void* result = malloc(length);
if (result) {
memcpy(result, mBuffer + MTP_CONTAINER_HEADER_SIZE, length);
- outLength = length;
+ *outLength = length;
return result;
}
}
- outLength = 0;
+ *outLength = 0;
return NULL;
}
diff --git a/media/mtp/MtpDataPacket.h b/media/mtp/MtpDataPacket.h
index 13d3bd9..6240f28 100644
--- a/media/mtp/MtpDataPacket.h
+++ b/media/mtp/MtpDataPacket.h
@@ -117,7 +117,7 @@
inline bool hasData() const { return mPacketSize > MTP_CONTAINER_HEADER_SIZE; }
inline uint32_t getContainerLength() const { return MtpPacket::getUInt32(MTP_CONTAINER_LENGTH_OFFSET); }
- void* getData(int& outLength) const;
+ void* getData(int* outLength) const;
};
}; // namespace android
diff --git a/media/mtp/MtpDebug.cpp b/media/mtp/MtpDebug.cpp
index 9f3037d..1c04bcf 100644
--- a/media/mtp/MtpDebug.cpp
+++ b/media/mtp/MtpDebug.cpp
@@ -101,6 +101,7 @@
{ "MTP_FORMAT_TIFF_IT", 0x380E },
{ "MTP_FORMAT_JP2", 0x380F },
{ "MTP_FORMAT_JPX", 0x3810 },
+ { "MTP_FORMAT_DNG", 0x3811 },
{ "MTP_FORMAT_UNDEFINED_FIRMWARE", 0xB802 },
{ "MTP_FORMAT_WINDOWS_IMAGE_FORMAT", 0xB881 },
{ "MTP_FORMAT_UNDEFINED_AUDIO", 0xB900 },
diff --git a/media/mtp/MtpDevice.cpp b/media/mtp/MtpDevice.cpp
index 3eafd6f..6f72a3e 100644
--- a/media/mtp/MtpDevice.cpp
+++ b/media/mtp/MtpDevice.cpp
@@ -19,6 +19,7 @@
#include "MtpDebug.h"
#include "MtpDevice.h"
#include "MtpDeviceInfo.h"
+#include "MtpEventPacket.h"
#include "MtpObjectInfo.h"
#include "MtpProperty.h"
#include "MtpStorageInfo.h"
@@ -50,6 +51,19 @@
}
#endif
+namespace {
+
+bool writeToFd(void* data, uint32_t /* unused_offset */, uint32_t length, void* clientData) {
+ const int fd = *static_cast<int*>(clientData);
+ const ssize_t result = write(fd, data, length);
+ if (result < 0) {
+ return false;
+ }
+ return static_cast<uint32_t>(result) == length;
+}
+
+} // namespace
+
MtpDevice* MtpDevice::open(const char* deviceName, int fd) {
struct usb_device *device = usb_device_new(deviceName, fd);
if (!device) {
@@ -123,6 +137,10 @@
printf("no MTP string\n");
}
}
+#else
+ else {
+ continue;
+ }
#endif
// if we got here, then we have a likely MTP or PTP device
@@ -194,7 +212,9 @@
mDeviceInfo(NULL),
mSessionID(0),
mTransactionID(0),
- mReceivedResponse(false)
+ mReceivedResponse(false),
+ mProcessingEvent(false),
+ mCurrentEventHandle(0)
{
mRequestIn1 = usb_request_new(device, ep_in);
mRequestIn2 = usb_request_new(device, ep_in);
@@ -414,7 +434,7 @@
if (sendRequest(MTP_OPERATION_GET_THUMB) && readData()) {
MtpResponseCode ret = readResponse();
if (ret == MTP_RESPONSE_OK) {
- return mData.getData(outLength);
+ return mData.getData(&outLength);
}
}
outLength = 0;
@@ -430,8 +450,9 @@
parent = MTP_PARENT_ROOT;
mRequest.setParameter(1, info->mStorageID);
- mRequest.setParameter(2, info->mParent);
+ mRequest.setParameter(2, parent);
+ mData.reset();
mData.putUInt32(info->mStorageID);
mData.putUInt16(info->mFormat);
mData.putUInt16(info->mProtectionStatus);
@@ -472,17 +493,18 @@
return (MtpObjectHandle)-1;
}
-bool MtpDevice::sendObject(MtpObjectInfo* info, int srcFD) {
+bool MtpDevice::sendObject(MtpObjectHandle handle, int size, int srcFD) {
Mutex::Autolock autoLock(mMutex);
- int remaining = info->mCompressedSize;
+ int remaining = size;
mRequest.reset();
- mRequest.setParameter(1, info->mHandle);
+ mRequest.setParameter(1, handle);
if (sendRequest(MTP_OPERATION_SEND_OBJECT)) {
// send data header
writeDataHeader(MTP_OPERATION_SEND_OBJECT, remaining);
- char buffer[65536];
+ // USB writes greater than 16K don't work
+ char buffer[MTP_BUFFER_SIZE];
while (remaining > 0) {
int count = read(srcFD, buffer, sizeof(buffer));
if (count > 0) {
@@ -592,97 +614,12 @@
}
bool MtpDevice::readObject(MtpObjectHandle handle,
- bool (* callback)(void* data, int offset, int length, void* clientData),
- size_t objectSize, void* clientData) {
- Mutex::Autolock autoLock(mMutex);
- bool result = false;
-
- mRequest.reset();
- mRequest.setParameter(1, handle);
- if (sendRequest(MTP_OPERATION_GET_OBJECT)
- && mData.readDataHeader(mRequestIn1)) {
- uint32_t length = mData.getContainerLength();
- if (length - MTP_CONTAINER_HEADER_SIZE != objectSize) {
- ALOGE("readObject error objectSize: %d, length: %d",
- objectSize, length);
- goto fail;
- }
- length -= MTP_CONTAINER_HEADER_SIZE;
- uint32_t remaining = length;
- int offset = 0;
-
- int initialDataLength = 0;
- void* initialData = mData.getData(initialDataLength);
- if (initialData) {
- if (initialDataLength > 0) {
- if (!callback(initialData, 0, initialDataLength, clientData))
- goto fail;
- remaining -= initialDataLength;
- offset += initialDataLength;
- }
- free(initialData);
- }
-
- // USB reads greater than 16K don't work
- char buffer1[16384], buffer2[16384];
- mRequestIn1->buffer = buffer1;
- mRequestIn2->buffer = buffer2;
- struct usb_request* req = mRequestIn1;
- void* writeBuffer = NULL;
- int writeLength = 0;
-
- while (remaining > 0 || writeBuffer) {
- if (remaining > 0) {
- // queue up a read request
- req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
- if (mData.readDataAsync(req)) {
- ALOGE("readDataAsync failed");
- goto fail;
- }
- } else {
- req = NULL;
- }
-
- if (writeBuffer) {
- // write previous buffer
- if (!callback(writeBuffer, offset, writeLength, clientData)) {
- ALOGE("write failed");
- // wait for pending read before failing
- if (req)
- mData.readDataWait(mDevice);
- goto fail;
- }
- offset += writeLength;
- writeBuffer = NULL;
- }
-
- // wait for read to complete
- if (req) {
- int read = mData.readDataWait(mDevice);
- if (read < 0)
- goto fail;
-
- if (read > 0) {
- writeBuffer = req->buffer;
- writeLength = read;
- remaining -= read;
- req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
- } else {
- writeBuffer = NULL;
- }
- }
- }
-
- MtpResponseCode response = readResponse();
- if (response == MTP_RESPONSE_OK)
- result = true;
- }
-
-fail:
- return result;
+ ReadObjectCallback callback,
+ uint32_t expectedLength,
+ void* clientData) {
+ return readObjectInternal(handle, callback, &expectedLength, clientData);
}
-
// reads the object's data and writes it to the specified file path
bool MtpDevice::readObject(MtpObjectHandle handle, const char* destPath, int group, int perm) {
ALOGD("readObject: %s", destPath);
@@ -698,89 +635,150 @@
fchmod(fd, perm);
umask(mask);
+ bool result = readObject(handle, fd);
+ ::close(fd);
+ return result;
+}
+
+bool MtpDevice::readObject(MtpObjectHandle handle, int fd) {
+ ALOGD("readObject: %d", fd);
+ return readObjectInternal(handle, writeToFd, NULL /* expected size */, &fd);
+}
+
+bool MtpDevice::readObjectInternal(MtpObjectHandle handle,
+ ReadObjectCallback callback,
+ const uint32_t* expectedLength,
+ void* clientData) {
Mutex::Autolock autoLock(mMutex);
- bool result = false;
mRequest.reset();
mRequest.setParameter(1, handle);
- if (sendRequest(MTP_OPERATION_GET_OBJECT)
- && mData.readDataHeader(mRequestIn1)) {
- uint32_t length = mData.getContainerLength();
- if (length < MTP_CONTAINER_HEADER_SIZE)
- goto fail;
- length -= MTP_CONTAINER_HEADER_SIZE;
- uint32_t remaining = length;
+ if (!sendRequest(MTP_OPERATION_GET_OBJECT)) {
+ ALOGE("Failed to send a read request.");
+ return false;
+ }
+ return readData(callback, expectedLength, nullptr, clientData);
+}
+
+bool MtpDevice::readData(ReadObjectCallback callback,
+ const uint32_t* expectedLength,
+ uint32_t* writtenSize,
+ void* clientData) {
+ if (!mData.readDataHeader(mRequestIn1)) {
+ ALOGE("Failed to read header.");
+ return false;
+ }
+
+ if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+ mResponse.copyFrom(mData);
+ return mResponse.getResponseCode() == MTP_RESPONSE_OK ? 0 : -1;
+ }
+
+ // If object size 0 byte, the remote device can reply response packet
+ // without sending any data packets.
+ if (mData.getContainerType() == MTP_CONTAINER_TYPE_RESPONSE) {
+ mResponse.copyFrom(mData);
+ return mResponse.getResponseCode() == MTP_RESPONSE_OK;
+ }
+
+ const uint32_t fullLength = mData.getContainerLength();
+ if (fullLength < MTP_CONTAINER_HEADER_SIZE) {
+ ALOGE("fullLength is too short: %d", fullLength);
+ return false;
+ }
+ const uint32_t length = fullLength - MTP_CONTAINER_HEADER_SIZE;
+ if (expectedLength && length != *expectedLength) {
+ ALOGE("readObject error length: %d", fullLength);
+ return false;
+ }
+
+ uint32_t offset = 0;
+ bool writingError = false;
+
+ {
int initialDataLength = 0;
- void* initialData = mData.getData(initialDataLength);
+ void* const initialData = mData.getData(&initialDataLength);
if (initialData) {
if (initialDataLength > 0) {
- if (write(fd, initialData, initialDataLength) != initialDataLength) {
- free(initialData);
- goto fail;
+ if (!callback(initialData, offset, initialDataLength, clientData)) {
+ ALOGE("Failed to write initial data.");
+ writingError = true;
}
- remaining -= initialDataLength;
+ offset += initialDataLength;
}
free(initialData);
}
+ }
- // USB reads greater than 16K don't work
- char buffer1[16384], buffer2[16384];
- mRequestIn1->buffer = buffer1;
- mRequestIn2->buffer = buffer2;
- struct usb_request* req = mRequestIn1;
+ // USB reads greater than 16K don't work.
+ char buffer1[MTP_BUFFER_SIZE], buffer2[MTP_BUFFER_SIZE];
+ mRequestIn1->buffer = buffer1;
+ mRequestIn2->buffer = buffer2;
+ struct usb_request* req = NULL;
+
+ while (offset < length) {
+ // Wait for previous read to complete.
void* writeBuffer = NULL;
int writeLength = 0;
-
- while (remaining > 0 || writeBuffer) {
- if (remaining > 0) {
- // queue up a read request
- req->buffer_length = (remaining > sizeof(buffer1) ? sizeof(buffer1) : remaining);
- if (mData.readDataAsync(req)) {
- ALOGE("readDataAsync failed");
- goto fail;
- }
- } else {
- req = NULL;
+ if (req) {
+ const int read = mData.readDataWait(mDevice);
+ if (read < 0) {
+ ALOGE("readDataWait failed.");
+ return false;
}
+ writeBuffer = req->buffer;
+ writeLength = read;
+ }
- if (writeBuffer) {
- // write previous buffer
- if (write(fd, writeBuffer, writeLength) != writeLength) {
- ALOGE("write failed");
- // wait for pending read before failing
- if (req)
- mData.readDataWait(mDevice);
- goto fail;
- }
- writeBuffer = NULL;
- }
-
- // wait for read to complete
- if (req) {
- int read = mData.readDataWait(mDevice);
- if (read < 0)
- goto fail;
-
- if (read > 0) {
- writeBuffer = req->buffer;
- writeLength = read;
- remaining -= read;
- req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
- } else {
- writeBuffer = NULL;
- }
+ // Request to read next chunk.
+ const uint32_t nextOffset = offset + writeLength;
+ if (nextOffset < length) {
+ // Queue up a read request.
+ const size_t remaining = length - nextOffset;
+ req = (req == mRequestIn1 ? mRequestIn2 : mRequestIn1);
+ req->buffer_length = remaining > MTP_BUFFER_SIZE ?
+ static_cast<size_t>(MTP_BUFFER_SIZE) : remaining;
+ if (mData.readDataAsync(req) != 0) {
+ ALOGE("readDataAsync failed");
+ return false;
}
}
- MtpResponseCode response = readResponse();
- if (response == MTP_RESPONSE_OK)
- result = true;
+ // Write previous buffer.
+ if (writeBuffer && !writingError) {
+ if (!callback(writeBuffer, offset, writeLength, clientData)) {
+ ALOGE("write failed");
+ writingError = true;
+ }
+ }
+ offset = nextOffset;
}
-fail:
- ::close(fd);
- return result;
+ if (writtenSize) {
+ *writtenSize = length;
+ }
+
+ return readResponse() == MTP_RESPONSE_OK;
+}
+
+bool MtpDevice::readPartialObject(MtpObjectHandle handle,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t *writtenSize,
+ ReadObjectCallback callback,
+ void* clientData) {
+ Mutex::Autolock autoLock(mMutex);
+
+ mRequest.reset();
+ mRequest.setParameter(1, handle);
+ mRequest.setParameter(2, offset);
+ mRequest.setParameter(3, size);
+ if (!sendRequest(MTP_OPERATION_GET_PARTIAL_OBJECT)) {
+ ALOGE("Failed to send a read request.");
+ return false;
+ }
+ return readData(callback, NULL /* expected size */, writtenSize, clientData);
}
bool MtpDevice::sendRequest(MtpOperationCode operation) {
@@ -800,7 +798,7 @@
mData.setTransactionID(mRequest.getTransactionID());
int ret = mData.write(mRequestOut);
mData.dump();
- return (ret > 0);
+ return (ret >= 0);
}
bool MtpDevice::readData() {
@@ -851,4 +849,44 @@
}
}
+int MtpDevice::submitEventRequest() {
+ if (mEventMutex.tryLock()) {
+ // An event is being reaped on another thread.
+ return -1;
+ }
+ if (mProcessingEvent) {
+ // An event request was submitted, but no reapEventRequest called so far.
+ return -1;
+ }
+ Mutex::Autolock autoLock(mEventMutexForInterrupt);
+ mEventPacket.sendRequest(mRequestIntr);
+ const int currentHandle = ++mCurrentEventHandle;
+ mProcessingEvent = true;
+ mEventMutex.unlock();
+ return currentHandle;
+}
+
+int MtpDevice::reapEventRequest(int handle, uint32_t (*parameters)[3]) {
+ Mutex::Autolock autoLock(mEventMutex);
+ if (!mProcessingEvent || mCurrentEventHandle != handle || !parameters) {
+ return -1;
+ }
+ mProcessingEvent = false;
+ const int readSize = mEventPacket.readResponse(mRequestIntr->dev);
+ const int result = mEventPacket.getEventCode();
+ // MTP event has three parameters.
+ (*parameters)[0] = mEventPacket.getParameter(1);
+ (*parameters)[1] = mEventPacket.getParameter(2);
+ (*parameters)[2] = mEventPacket.getParameter(3);
+ return readSize != 0 ? result : 0;
+}
+
+void MtpDevice::discardEventRequest(int handle) {
+ Mutex::Autolock autoLock(mEventMutexForInterrupt);
+ if (mCurrentEventHandle != handle) {
+ return;
+ }
+ usb_request_cancel(mRequestIntr);
+}
+
} // namespace android
diff --git a/media/mtp/MtpDevice.h b/media/mtp/MtpDevice.h
index 9b0acbf..edc608f 100644
--- a/media/mtp/MtpDevice.h
+++ b/media/mtp/MtpDevice.h
@@ -17,8 +17,9 @@
#ifndef _MTP_DEVICE_H
#define _MTP_DEVICE_H
-#include "MtpRequestPacket.h"
+#include "MtpEventPacket.h"
#include "MtpDataPacket.h"
+#include "MtpRequestPacket.h"
#include "MtpResponsePacket.h"
#include "MtpTypes.h"
@@ -31,6 +32,7 @@
namespace android {
class MtpDeviceInfo;
+class MtpEventPacket;
class MtpObjectInfo;
class MtpStorageInfo;
@@ -53,17 +55,27 @@
MtpRequestPacket mRequest;
MtpDataPacket mData;
MtpResponsePacket mResponse;
+ MtpEventPacket mEventPacket;
+
// set to true if we received a response packet instead of a data packet
bool mReceivedResponse;
+ bool mProcessingEvent;
+ int mCurrentEventHandle;
// to ensure only one MTP transaction at a time
Mutex mMutex;
+ Mutex mEventMutex;
+ Mutex mEventMutexForInterrupt;
public:
- MtpDevice(struct usb_device* device, int interface,
- const struct usb_endpoint_descriptor *ep_in,
- const struct usb_endpoint_descriptor *ep_out,
- const struct usb_endpoint_descriptor *ep_intr);
+ typedef bool (*ReadObjectCallback)
+ (void* data, uint32_t offset, uint32_t length, void* clientData);
+
+ MtpDevice(struct usb_device* device,
+ int interface,
+ const struct usb_endpoint_descriptor *ep_in,
+ const struct usb_endpoint_descriptor *ep_out,
+ const struct usb_endpoint_descriptor *ep_intr);
static MtpDevice* open(const char* deviceName, int fd);
@@ -85,7 +97,7 @@
MtpObjectInfo* getObjectInfo(MtpObjectHandle handle);
void* getThumbnail(MtpObjectHandle handle, int& outLength);
MtpObjectHandle sendObjectInfo(MtpObjectInfo* info);
- bool sendObject(MtpObjectInfo* info, int srcFD);
+ bool sendObject(MtpObjectHandle handle, int size, int srcFD);
bool deleteObject(MtpObjectHandle handle);
MtpObjectHandle getParent(MtpObjectHandle handle);
MtpObjectHandle getStorageID(MtpObjectHandle handle);
@@ -95,20 +107,47 @@
MtpProperty* getDevicePropDesc(MtpDeviceProperty code);
MtpProperty* getObjectPropDesc(MtpObjectProperty code, MtpObjectFormat format);
- bool readObject(MtpObjectHandle handle,
- bool (* callback)(void* data, int offset,
- int length, void* clientData),
- size_t objectSize, void* clientData);
+ bool readObject(MtpObjectHandle handle, ReadObjectCallback callback,
+ uint32_t objectSize, void* clientData);
bool readObject(MtpObjectHandle handle, const char* destPath, int group,
int perm);
+ bool readObject(MtpObjectHandle handle, int fd);
+ bool readPartialObject(MtpObjectHandle handle,
+ uint32_t offset,
+ uint32_t size,
+ uint32_t *writtenSize,
+ ReadObjectCallback callback,
+ void* clientData);
+ // Starts a request to read MTP event from MTP device. It returns a request handle that
+ // can be used for blocking read or cancel. If other thread has already been processing an
+ // event returns -1.
+ int submitEventRequest();
+ // Waits for MTP event from the device and returns MTP event code. It blocks the current thread
+ // until it receives an event from the device. |handle| should be a request handle returned
+ // by |submitEventRequest|. The function writes event parameters to |parameters|. Returns 0 for
+ // cancellations. Returns -1 for errors.
+ int reapEventRequest(int handle, uint32_t (*parameters)[3]);
+ // Cancels an event request. |handle| should be request handle returned by
+ // |submitEventRequest|. If there is a thread blocked by |reapEventRequest| with the same
+ // |handle|, the thread will resume.
+ void discardEventRequest(int handle);
private:
+ // If |objectSize| is not NULL, it checks object size before reading data bytes.
+ bool readObjectInternal(MtpObjectHandle handle,
+ ReadObjectCallback callback,
+ const uint32_t* objectSize,
+ void* clientData);
+ // If |objectSize| is not NULL, it checks object size before reading data bytes.
+ bool readData(ReadObjectCallback callback,
+ const uint32_t* objectSize,
+ uint32_t* writtenData,
+ void* clientData);
bool sendRequest(MtpOperationCode operation);
bool sendData();
bool readData();
bool writeDataHeader(MtpOperationCode operation, int dataLength);
MtpResponseCode readResponse();
-
};
}; // namespace android
diff --git a/media/mtp/MtpEventPacket.cpp b/media/mtp/MtpEventPacket.cpp
index d2fca42..8e13ea9 100644
--- a/media/mtp/MtpEventPacket.cpp
+++ b/media/mtp/MtpEventPacket.cpp
@@ -54,17 +54,26 @@
#endif
#ifdef MTP_HOST
-int MtpEventPacket::read(struct usb_request *request) {
+int MtpEventPacket::sendRequest(struct usb_request *request) {
request->buffer = mBuffer;
request->buffer_length = mBufferSize;
- int ret = transfer(request);
- if (ret >= 0)
- mPacketSize = ret;
- else
- mPacketSize = 0;
- return ret;
+ mPacketSize = 0;
+ if (usb_request_queue(request)) {
+ ALOGE("usb_endpoint_queue failed, errno: %d", errno);
+ return -1;
+ }
+ return 0;
+}
+
+int MtpEventPacket::readResponse(struct usb_device *device) {
+ struct usb_request* const req = usb_request_wait(device);
+ if (req) {
+ mPacketSize = req->actual_length;
+ return req->actual_length;
+ } else {
+ return -1;
+ }
}
#endif
} // namespace android
-
diff --git a/media/mtp/MtpEventPacket.h b/media/mtp/MtpEventPacket.h
index 660baad..a8779fd 100644
--- a/media/mtp/MtpEventPacket.h
+++ b/media/mtp/MtpEventPacket.h
@@ -35,7 +35,8 @@
#ifdef MTP_HOST
// read our buffer with the given request
- int read(struct usb_request *request);
+ int sendRequest(struct usb_request *request);
+ int readResponse(struct usb_device *device);
#endif
inline MtpEventCode getEventCode() const { return getContainerCode(); }
diff --git a/media/mtp/MtpPacket.h b/media/mtp/MtpPacket.h
index 037722a..0e96309 100644
--- a/media/mtp/MtpPacket.h
+++ b/media/mtp/MtpPacket.h
@@ -19,6 +19,7 @@
#include "MtpTypes.h"
+struct usb_device;
struct usb_request;
namespace android {
diff --git a/media/mtp/mtp.h b/media/mtp/mtp.h
index d270df5..adfb102 100644
--- a/media/mtp/mtp.h
+++ b/media/mtp/mtp.h
@@ -37,6 +37,9 @@
#define MTP_CONTAINER_PARAMETER_OFFSET 12
#define MTP_CONTAINER_HEADER_SIZE 12
+// Maximum buffer size for a MTP packet.
+#define MTP_BUFFER_SIZE 16384
+
// MTP Data Types
#define MTP_TYPE_UNDEFINED 0x0000 // Undefined
#define MTP_TYPE_INT8 0x0001 // Signed 8-bit integer
@@ -90,6 +93,7 @@
#define MTP_FORMAT_TIFF_IT 0x380E // Tag Image File Format for Information Technology (graphic arts)
#define MTP_FORMAT_JP2 0x380F // JPEG2000 Baseline File Format
#define MTP_FORMAT_JPX 0x3810 // JPEG2000 Extended File Format
+#define MTP_FORMAT_DNG 0x3811 // Digital Negative
#define MTP_FORMAT_UNDEFINED_FIRMWARE 0xB802
#define MTP_FORMAT_WINDOWS_IMAGE_FORMAT 0xB881
#define MTP_FORMAT_UNDEFINED_AUDIO 0xB900
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index cd0c462..8e36065 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -372,6 +372,7 @@
uint8_t key[16];
uint8_t iv[16];
cryptoinfo_mode_t mode;
+ cryptoinfo_pattern_t pattern;
size_t *clearbytes;
size_t *encryptedbytes;
} AMediaCodecCryptoInfo;
@@ -391,6 +392,10 @@
subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i];
}
+ CryptoPlugin::Pattern pattern;
+ pattern.mEncryptBlocks = crypto->pattern.encryptBlocks;
+ pattern.mSkipBlocks = crypto->pattern.skipBlocks;
+
AString errormsg;
status_t err = codec->mCodec->queueSecureInputBuffer(idx,
offset,
@@ -398,7 +403,8 @@
crypto->numsubsamples,
crypto->key,
crypto->iv,
- (CryptoPlugin::Mode) crypto->mode,
+ (CryptoPlugin::Mode)crypto->mode,
+ pattern,
time,
flags,
&errormsg);
@@ -410,6 +416,12 @@
}
+EXPORT
+void AMediaCodecCryptoInfo_setPattern(AMediaCodecCryptoInfo *info,
+ cryptoinfo_pattern_t *pattern) {
+ info->pattern.encryptBlocks = pattern->encryptBlocks;
+ info->pattern.skipBlocks = pattern->skipBlocks;
+}
EXPORT
AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new(
@@ -431,6 +443,8 @@
memcpy(ret->key, key, 16);
memcpy(ret->iv, iv, 16);
ret->mode = mode;
+ ret->pattern.encryptBlocks = 0;
+ ret->pattern.skipBlocks = 0;
// clearbytes and encryptedbytes point at the actual data, which follows
ret->clearbytes = (size_t*) (ret + 1); // point immediately after the struct
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 0ecd64f..b869c54 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -243,15 +243,27 @@
while (len > 0) {
numentries++;
+ if (len < 16) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
// skip uuid
data += 16;
len -= 16;
// get data length
+ if (len < 4) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
uint32_t datalen = *((uint32_t*)data);
data += 4;
len -= 4;
+ if (len < datalen) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
// skip the data
data += datalen;
len -= datalen;
@@ -265,6 +277,10 @@
// extra pointer for each entry, and an extra size_t for the entire PsshInfo.
size_t newsize = buffer->size() - (sizeof(uint32_t) * numentries) + sizeof(size_t)
+ ((sizeof(void*) + sizeof(size_t)) * numentries);
+ if (newsize <= buffer->size()) {
+ ALOGE("invalid PSSH data");
+ return NULL;
+ }
ex->mPsshBuf = new ABuffer(newsize);
ex->mPsshBuf->setRange(0, newsize);
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index a354d58..5598d5d 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -46,6 +46,10 @@
ALOGV("private ctor");
AMediaFormat* mData = new AMediaFormat();
mData->mFormat = *((sp<AMessage>*)data);
+ if (mData->mFormat == NULL) {
+ ALOGW("got NULL format");
+ mData->mFormat = new AMessage;
+ }
return mData;
}
diff --git a/media/utils/BatteryNotifier.cpp b/media/utils/BatteryNotifier.cpp
index 7f9cd7a..341d391 100644
--- a/media/utils/BatteryNotifier.cpp
+++ b/media/utils/BatteryNotifier.cpp
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#define LOG_TAG "BatteryNotifier"
+//#define LOG_NDEBUG 0
+
#include "include/mediautils/BatteryNotifier.h"
#include <binder/IServiceManager.h>
@@ -64,7 +67,7 @@
sp<IBatteryStats> batteryService = getBatteryService_l();
mVideoRefCount = 0;
if (batteryService != nullptr) {
- batteryService->noteResetAudio();
+ batteryService->noteResetVideo();
}
}
@@ -72,7 +75,7 @@
Mutex::Autolock _l(mLock);
sp<IBatteryStats> batteryService = getBatteryService_l();
if (mAudioRefCount == 0 && batteryService != nullptr) {
- batteryService->noteStartAudio(AID_MEDIA);
+ batteryService->noteStartAudio(AID_AUDIOSERVER);
}
mAudioRefCount++;
}
@@ -88,7 +91,7 @@
mAudioRefCount--;
if (mAudioRefCount == 0 && batteryService != nullptr) {
- batteryService->noteStopAudio(AID_MEDIA);
+ batteryService->noteStopAudio(AID_AUDIOSERVER);
}
}
@@ -190,20 +193,25 @@
const String16 name("batterystats");
mBatteryStatService = interface_cast<IBatteryStats>(sm->checkService(name));
if (mBatteryStatService == nullptr) {
- ALOGE("batterystats service unavailable!");
+ // this may occur normally during the init sequence as mediaserver
+ // and audioserver start before the batterystats service is available.
+ ALOGW("batterystats service unavailable!");
return nullptr;
}
mDeathNotifier = new DeathNotifier();
IInterface::asBinder(mBatteryStatService)->linkToDeath(mDeathNotifier);
- // Notify start now if media already started
+ // Notify start now if mediaserver or audioserver is already started.
+ // 1) mediaserver and audioserver is started before batterystats service
+ // 2) batterystats server may have crashed.
if (mVideoRefCount > 0) {
mBatteryStatService->noteStartVideo(AID_MEDIA);
}
if (mAudioRefCount > 0) {
- mBatteryStatService->noteStartAudio(AID_MEDIA);
+ mBatteryStatService->noteStartAudio(AID_AUDIOSERVER);
}
+ // TODO: Notify for camera and flashlight state as well?
}
return mBatteryStatService;
}
diff --git a/radio/IRadioService.cpp b/radio/IRadioService.cpp
index 8c2b3ef..81acf9e 100644
--- a/radio/IRadioService.cpp
+++ b/radio/IRadioService.cpp
@@ -87,7 +87,8 @@
data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
data.writeInt32(handle);
data.writeStrongBinder(IInterface::asBinder(client));
- ALOGV("attach() config %p withAudio %d region %d type %d", config, withAudio, config->region, config->band.type);
+ ALOGV("attach() config %p withAudio %d region %d type %d",
+ config == NULL ? 0 : config, withAudio, config->region, config->band.type);
if (config == NULL) {
data.writeInt32(0);
} else {
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 9b4ba79..87f9aaa 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -47,6 +47,7 @@
liblog \
libbinder \
libmedia \
+ libmediautils \
libnbaio \
libhardware \
libhardware_legacy \
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index fab1ef5..d2786b9 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -63,6 +63,7 @@
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <media/AudioParameter.h>
+#include <mediautils/BatteryNotifier.h>
#include <private/android_filesystem_config.h>
// ----------------------------------------------------------------------------
@@ -184,13 +185,18 @@
mSystemReady(false)
{
getpid_cached = getpid();
- char value[PROPERTY_VALUE_MAX];
- bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
+ // disable media.log until the service is reenabled, see b/26306954
+ const bool doLog = false; // property_get_bool("ro.test_harness", false);
if (doLog) {
mLogMemoryDealer = new MemoryDealer(kLogMemorySize, "LogWriters",
MemoryHeapBase::READ_ONLY);
}
+ // reset battery stats.
+ // if the audio service has crashed, battery stats could be left
+ // in bad state, reset the state upon service start.
+ BatteryNotifier::getInstance().noteResetAudio();
+
#ifdef TEE_SINK
(void) property_get("ro.debuggable", value, "0");
int debuggable = atoi(value);
@@ -255,16 +261,17 @@
}
// Tell media.log service about any old writers that still need to be unregistered
- sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
- if (binder != 0) {
- sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
- for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
- sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
- mUnregisteredWriters.pop();
- mediaLogService->unregisterWriter(iMemory);
+ if (mLogMemoryDealer != 0) {
+ sp<IBinder> binder = defaultServiceManager()->getService(String16("media.log"));
+ if (binder != 0) {
+ sp<IMediaLogService> mediaLogService(interface_cast<IMediaLogService>(binder));
+ for (size_t count = mUnregisteredWriters.size(); count > 0; count--) {
+ sp<IMemory> iMemory(mUnregisteredWriters.top()->getIMemory());
+ mUnregisteredWriters.pop();
+ mediaLogService->unregisterWriter(iMemory);
+ }
}
}
-
}
static const char * const audio_interfaces[] = {
@@ -1451,8 +1458,15 @@
cblk.clear();
buffers.clear();
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid)) {
+ ALOGW_IF((uid_t)clientUid != callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
+ clientUid = callingUid;
+ }
+
// check calling permissions
- if (!recordingAllowed(opPackageName)) {
+ if (!recordingAllowed(opPackageName, tid, clientUid)) {
ALOGE("openRecord() permission denied: recording not allowed");
lStatus = PERMISSION_DENIED;
goto Exit;
@@ -1502,7 +1516,6 @@
}
ALOGV("openRecord() lSessionId: %d input %d", lSessionId, input);
- // TODO: the uid should be passed in as a parameter to openRecord
recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
frameCount, lSessionId, notificationFrames,
clientUid, flags, tid, &lStatus);
@@ -2585,7 +2598,7 @@
// check recording permission for visualizer
if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) &&
- !recordingAllowed(opPackageName)) {
+ !recordingAllowed(opPackageName, pid, IPCThreadState::self()->getCallingUid())) {
lStatus = PERMISSION_DENIED;
goto Exit;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 08fa70d..2571e67 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -78,14 +78,6 @@
// ----------------------------------------------------------------------------
-// The macro FCC_2 highlights some (but not all) places where there are are 2-channel assumptions.
-// This is typically due to legacy implementation of stereo input or output.
-// Search also for "2", "left", "right", "[0]", "[1]", ">> 16", "<< 16", etc.
-#define FCC_2 2 // FCC_2 = Fixed Channel Count 2
-// The macro FCC_8 highlights places where there are 8-channel assumptions.
-// This is typically due to audio mixer and resampler limitations.
-#define FCC_8 8 // FCC_8 = Fixed Channel Count 8
-
static const nsecs_t kDefaultStandbyTimeInNsecs = seconds(3);
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index 45c68b5..3f99b43 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -37,12 +37,11 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
#endif
+#include <audio_utils/conversion.h>
#include <audio_utils/format.h>
#include "AudioMixer.h"
#include "FastMixer.h"
-#define FCC_2 2 // fixed channel count assumption
-
namespace android {
/*static*/ const FastMixerState FastMixer::sInitial;
@@ -66,7 +65,8 @@
mFastTracksGen(0),
mTotalNativeFramesWritten(0),
// timestamp
- mNativeFramesWrittenButNotPresented(0) // the = 0 is to silence the compiler
+ mNativeFramesWrittenButNotPresented(0), // the = 0 is to silence the compiler
+ mMasterMono(false)
{
// FIXME pass sInitial as parameter to base class constructor, and make it static local
mPrevious = &sInitial;
@@ -419,6 +419,10 @@
memset(mMixerBuffer, 0, mMixerBufferSize);
mMixerBufferState = ZEROED;
}
+
+ if (mMasterMono.load()) { // memory_order_seq_cst
+ mono_blend(mMixerBuffer, mMixerBufferFormat, Format_channelCount(mFormat), frameCount);
+ }
// prepare the buffer used to write to sink
void *buffer = mSinkBuffer != NULL ? mSinkBuffer : mMixerBuffer;
if (mFormat.mFormat != mMixerBufferFormat) { // sink format not the same as mixer format
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 06a68fb..e38878e 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_AUDIO_FAST_MIXER_H
#define ANDROID_AUDIO_FAST_MIXER_H
+#include <atomic>
#include "FastThread.h"
#include "StateQueue.h"
#include "FastMixerState.h"
@@ -36,6 +37,8 @@
FastMixerStateQueue* sq();
+ virtual void setMasterMono(bool mono) { mMasterMono.store(mono); /* memory_order_seq_cst */ }
+
private:
FastMixerStateQueue mSQ;
@@ -82,6 +85,8 @@
AudioTimestamp mTimestamp;
uint32_t mNativeFramesWrittenButNotPresented;
+ // accessed without lock between multiple threads.
+ std::atomic_bool mMasterMono;
}; // class FastMixer
} // namespace android
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index f6078a2..a6cb9c0 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -152,7 +152,8 @@
return BAD_VALUE;
}
if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
- patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
+ (patch->num_sinks == 0 && patch->num_sources != 2) ||
+ patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
return BAD_VALUE;
}
// limit number of sources to 1 for now or 2 sources for special cross hw module case.
@@ -203,18 +204,18 @@
}
// manage patches requiring a software bridge
+ // - special patch request with 2 sources (reuse one existing output mix) OR
// - Device to device AND
// - source HW module != destination HW module OR
// - audio HAL version < 3.0
- // - special patch request with 2 sources (reuse one existing output mix)
- if ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
- ((patch->sinks[0].ext.device.hw_module != srcModule) ||
- (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) ||
- (patch->num_sources == 2))) {
+ if ((patch->num_sources == 2) ||
+ ((patch->sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
+ ((patch->sinks[0].ext.device.hw_module != srcModule) ||
+ (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0)))) {
if (patch->num_sources == 2) {
if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
- patch->sinks[0].ext.device.hw_module !=
- patch->sources[1].ext.mix.hw_module) {
+ (patch->num_sinks != 0 && patch->sinks[0].ext.device.hw_module !=
+ patch->sources[1].ext.mix.hw_module)) {
ALOGW("createAudioPatch() invalid source combination");
status = INVALID_OPERATION;
goto exit;
@@ -379,12 +380,16 @@
}
// create patch from playback thread output to sink device
- patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
- subPatch.sinks[0] = audioPatch->sinks[0];
- status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
- if (status != NO_ERROR) {
+ if (audioPatch->num_sinks != 0) {
+ patch->mPlaybackThread->getAudioPortConfig(&subPatch.sources[0]);
+ subPatch.sinks[0] = audioPatch->sinks[0];
+ status = createAudioPatch(&subPatch, &patch->mPlaybackPatchHandle);
+ if (status != NO_ERROR) {
+ patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ return status;
+ }
+ } else {
patch->mPlaybackPatchHandle = AUDIO_PATCH_HANDLE_NONE;
- return status;
}
// use a pseudo LCM between input and output framecount
diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp
index 2e68dad..afc2440 100644
--- a/services/audioflinger/ServiceUtilities.cpp
+++ b/services/audioflinger/ServiceUtilities.cpp
@@ -32,29 +32,37 @@
// Not valid until initialized by AudioFlinger constructor. It would have to be
// re-initialized if the process containing AudioFlinger service forks (which it doesn't).
+// This is often used to validate binder interface calls within audioserver
+// (e.g. AudioPolicyManager to AudioFlinger).
pid_t getpid_cached;
-bool recordingAllowed(const String16& opPackageName) {
- // Note: We are getting the UID from the calling IPC thread state because all
- // clients that perform recording create AudioRecord in their own processes
- // and the system does not create AudioRecord objects on behalf of apps. This
- // differs from playback where in some situations the system recreates AudioTrack
- // instances associated with a client's MediaPlayer on behalf of this client.
- // In the latter case we have to store the client UID and pass in along for
- // security checks.
+// A trusted calling UID may specify the client UID as part of a binder interface call.
+// otherwise the calling UID must be equal to the client UID.
+bool isTrustedCallingUid(uid_t uid) {
+ switch (uid) {
+ case AID_MEDIA:
+ case AID_AUDIOSERVER:
+ return true;
+ default:
+ return false;
+ }
+}
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid) {
+ // we're always OK.
if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true;
+
static const String16 sRecordAudio("android.permission.RECORD_AUDIO");
+ // We specify a pid and uid here as mediaserver (aka MediaRecorder or StageFrightRecorder)
+ // may open a record track on behalf of a client. Note that pid may be a tid.
// IMPORTANT: Don't use PermissionCache - a runtime permission and may change.
- const bool ok = checkCallingPermission(sRecordAudio);
+ const bool ok = checkPermission(sRecordAudio, pid, uid);
if (!ok) {
ALOGE("Request requires android.permission.RECORD_AUDIO");
return false;
}
- const uid_t uid = IPCThreadState::self()->getCallingUid();
-
// To permit command-line native tests
if (uid == AID_ROOT) return true;
diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h
index fba6dce..1e79553 100644
--- a/services/audioflinger/ServiceUtilities.h
+++ b/services/audioflinger/ServiceUtilities.h
@@ -19,8 +19,8 @@
namespace android {
extern pid_t getpid_cached;
-
-bool recordingAllowed(const String16& opPackageName);
+bool isTrustedCallingUid(uid_t uid);
+bool recordingAllowed(const String16& opPackageName, pid_t pid, uid_t uid);
bool captureAudioOutputAllowed();
bool captureHotwordAllowed();
bool settingsAllowed();
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 71fc498..65166b0 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -36,6 +36,7 @@
#include <hardware/audio.h>
#include <audio_effects/effect_ns.h>
#include <audio_effects/effect_aec.h>
+#include <audio_utils/conversion.h>
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/minifloat.h>
@@ -48,6 +49,7 @@
#include <media/nbaio/Pipe.h>
#include <media/nbaio/PipeReader.h>
#include <media/nbaio/SourceAudioBufferProvider.h>
+#include <mediautils/BatteryNotifier.h>
#include <powermanager/PowerManager.h>
@@ -357,54 +359,54 @@
audio_devices_t mDevices;
const char * mString;
} mappingsOut[] = {
- AUDIO_DEVICE_OUT_EARPIECE, "EARPIECE",
- AUDIO_DEVICE_OUT_SPEAKER, "SPEAKER",
- AUDIO_DEVICE_OUT_WIRED_HEADSET, "WIRED_HEADSET",
- AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "WIRED_HEADPHONE",
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "BLUETOOTH_SCO",
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET",
- AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "BLUETOOTH_SCO_CARKIT",
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "BLUETOOTH_A2DP",
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES, "BLUETOOTH_A2DP_HEADPHONES",
- AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "BLUETOOTH_A2DP_SPEAKER",
- AUDIO_DEVICE_OUT_AUX_DIGITAL, "AUX_DIGITAL",
- AUDIO_DEVICE_OUT_HDMI, "HDMI",
- AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET",
- AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET",
- AUDIO_DEVICE_OUT_USB_ACCESSORY, "USB_ACCESSORY",
- AUDIO_DEVICE_OUT_USB_DEVICE, "USB_DEVICE",
- AUDIO_DEVICE_OUT_TELEPHONY_TX, "TELEPHONY_TX",
- AUDIO_DEVICE_OUT_LINE, "LINE",
- AUDIO_DEVICE_OUT_HDMI_ARC, "HDMI_ARC",
- AUDIO_DEVICE_OUT_SPDIF, "SPDIF",
- AUDIO_DEVICE_OUT_FM, "FM",
- AUDIO_DEVICE_OUT_AUX_LINE, "AUX_LINE",
- AUDIO_DEVICE_OUT_SPEAKER_SAFE, "SPEAKER_SAFE",
- AUDIO_DEVICE_OUT_IP, "IP",
- AUDIO_DEVICE_NONE, "NONE", // must be last
+ {AUDIO_DEVICE_OUT_EARPIECE, "EARPIECE"},
+ {AUDIO_DEVICE_OUT_SPEAKER, "SPEAKER"},
+ {AUDIO_DEVICE_OUT_WIRED_HEADSET, "WIRED_HEADSET"},
+ {AUDIO_DEVICE_OUT_WIRED_HEADPHONE, "WIRED_HEADPHONE"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO, "BLUETOOTH_SCO"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT, "BLUETOOTH_SCO_CARKIT"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "BLUETOOTH_A2DP"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"BLUETOOTH_A2DP_HEADPHONES"},
+ {AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER, "BLUETOOTH_A2DP_SPEAKER"},
+ {AUDIO_DEVICE_OUT_AUX_DIGITAL, "AUX_DIGITAL"},
+ {AUDIO_DEVICE_OUT_HDMI, "HDMI"},
+ {AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET,"ANLG_DOCK_HEADSET"},
+ {AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET,"DGTL_DOCK_HEADSET"},
+ {AUDIO_DEVICE_OUT_USB_ACCESSORY, "USB_ACCESSORY"},
+ {AUDIO_DEVICE_OUT_USB_DEVICE, "USB_DEVICE"},
+ {AUDIO_DEVICE_OUT_TELEPHONY_TX, "TELEPHONY_TX"},
+ {AUDIO_DEVICE_OUT_LINE, "LINE"},
+ {AUDIO_DEVICE_OUT_HDMI_ARC, "HDMI_ARC"},
+ {AUDIO_DEVICE_OUT_SPDIF, "SPDIF"},
+ {AUDIO_DEVICE_OUT_FM, "FM"},
+ {AUDIO_DEVICE_OUT_AUX_LINE, "AUX_LINE"},
+ {AUDIO_DEVICE_OUT_SPEAKER_SAFE, "SPEAKER_SAFE"},
+ {AUDIO_DEVICE_OUT_IP, "IP"},
+ {AUDIO_DEVICE_NONE, "NONE"}, // must be last
}, mappingsIn[] = {
- AUDIO_DEVICE_IN_COMMUNICATION, "COMMUNICATION",
- AUDIO_DEVICE_IN_AMBIENT, "AMBIENT",
- AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC",
- AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET",
- AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET",
- AUDIO_DEVICE_IN_AUX_DIGITAL, "AUX_DIGITAL",
- AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL",
- AUDIO_DEVICE_IN_TELEPHONY_RX, "TELEPHONY_RX",
- AUDIO_DEVICE_IN_BACK_MIC, "BACK_MIC",
- AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX",
- AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET",
- AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET",
- AUDIO_DEVICE_IN_USB_ACCESSORY, "USB_ACCESSORY",
- AUDIO_DEVICE_IN_USB_DEVICE, "USB_DEVICE",
- AUDIO_DEVICE_IN_FM_TUNER, "FM_TUNER",
- AUDIO_DEVICE_IN_TV_TUNER, "TV_TUNER",
- AUDIO_DEVICE_IN_LINE, "LINE",
- AUDIO_DEVICE_IN_SPDIF, "SPDIF",
- AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "BLUETOOTH_A2DP",
- AUDIO_DEVICE_IN_LOOPBACK, "LOOPBACK",
- AUDIO_DEVICE_IN_IP, "IP",
- AUDIO_DEVICE_NONE, "NONE", // must be last
+ {AUDIO_DEVICE_IN_COMMUNICATION, "COMMUNICATION"},
+ {AUDIO_DEVICE_IN_AMBIENT, "AMBIENT"},
+ {AUDIO_DEVICE_IN_BUILTIN_MIC, "BUILTIN_MIC"},
+ {AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, "BLUETOOTH_SCO_HEADSET"},
+ {AUDIO_DEVICE_IN_WIRED_HEADSET, "WIRED_HEADSET"},
+ {AUDIO_DEVICE_IN_AUX_DIGITAL, "AUX_DIGITAL"},
+ {AUDIO_DEVICE_IN_VOICE_CALL, "VOICE_CALL"},
+ {AUDIO_DEVICE_IN_TELEPHONY_RX, "TELEPHONY_RX"},
+ {AUDIO_DEVICE_IN_BACK_MIC, "BACK_MIC"},
+ {AUDIO_DEVICE_IN_REMOTE_SUBMIX, "REMOTE_SUBMIX"},
+ {AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET, "ANLG_DOCK_HEADSET"},
+ {AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET, "DGTL_DOCK_HEADSET"},
+ {AUDIO_DEVICE_IN_USB_ACCESSORY, "USB_ACCESSORY"},
+ {AUDIO_DEVICE_IN_USB_DEVICE, "USB_DEVICE"},
+ {AUDIO_DEVICE_IN_FM_TUNER, "FM_TUNER"},
+ {AUDIO_DEVICE_IN_TV_TUNER, "TV_TUNER"},
+ {AUDIO_DEVICE_IN_LINE, "LINE"},
+ {AUDIO_DEVICE_IN_SPDIF, "SPDIF"},
+ {AUDIO_DEVICE_IN_BLUETOOTH_A2DP, "BLUETOOTH_A2DP"},
+ {AUDIO_DEVICE_IN_LOOPBACK, "LOOPBACK"},
+ {AUDIO_DEVICE_IN_IP, "IP"},
+ {AUDIO_DEVICE_NONE, "NONE"}, // must be last
};
String8 result;
audio_devices_t allDevices = AUDIO_DEVICE_NONE;
@@ -442,9 +444,11 @@
audio_input_flags_t mFlag;
const char * mString;
} mappings[] = {
- AUDIO_INPUT_FLAG_FAST, "FAST",
- AUDIO_INPUT_FLAG_HW_HOTWORD, "HW_HOTWORD",
- AUDIO_INPUT_FLAG_NONE, "NONE", // must be last
+ {AUDIO_INPUT_FLAG_FAST, "FAST"},
+ {AUDIO_INPUT_FLAG_HW_HOTWORD, "HW_HOTWORD"},
+ {AUDIO_INPUT_FLAG_RAW, "RAW"},
+ {AUDIO_INPUT_FLAG_SYNC, "SYNC"},
+ {AUDIO_INPUT_FLAG_NONE, "NONE"}, // must be last
};
String8 result;
audio_input_flags_t allFlags = AUDIO_INPUT_FLAG_NONE;
@@ -476,14 +480,17 @@
audio_output_flags_t mFlag;
const char * mString;
} mappings[] = {
- AUDIO_OUTPUT_FLAG_DIRECT, "DIRECT",
- AUDIO_OUTPUT_FLAG_PRIMARY, "PRIMARY",
- AUDIO_OUTPUT_FLAG_FAST, "FAST",
- AUDIO_OUTPUT_FLAG_DEEP_BUFFER, "DEEP_BUFFER",
- AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD, "COMPRESS_OFFLOAD",
- AUDIO_OUTPUT_FLAG_NON_BLOCKING, "NON_BLOCKING",
- AUDIO_OUTPUT_FLAG_HW_AV_SYNC, "HW_AV_SYNC",
- AUDIO_OUTPUT_FLAG_NONE, "NONE", // must be last
+ {AUDIO_OUTPUT_FLAG_DIRECT, "DIRECT"},
+ {AUDIO_OUTPUT_FLAG_PRIMARY, "PRIMARY"},
+ {AUDIO_OUTPUT_FLAG_FAST, "FAST"},
+ {AUDIO_OUTPUT_FLAG_DEEP_BUFFER, "DEEP_BUFFER"},
+ {AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD,"COMPRESS_OFFLOAD"},
+ {AUDIO_OUTPUT_FLAG_NON_BLOCKING, "NON_BLOCKING"},
+ {AUDIO_OUTPUT_FLAG_HW_AV_SYNC, "HW_AV_SYNC"},
+ {AUDIO_OUTPUT_FLAG_RAW, "RAW"},
+ {AUDIO_OUTPUT_FLAG_SYNC, "SYNC"},
+ {AUDIO_OUTPUT_FLAG_IEC958_NONAUDIO, "IEC958_NONAUDIO"},
+ {AUDIO_OUTPUT_FLAG_NONE, "NONE"}, // must be last
};
String8 result;
audio_output_flags_t allFlags = AUDIO_OUTPUT_FLAG_NONE;
@@ -521,6 +528,7 @@
case AUDIO_SOURCE_VOICE_RECOGNITION: return "voice recognition";
case AUDIO_SOURCE_VOICE_COMMUNICATION: return "voice communication";
case AUDIO_SOURCE_REMOTE_SUBMIX: return "remote submix";
+ case AUDIO_SOURCE_UNPROCESSED: return "unprocessed";
case AUDIO_SOURCE_FM_TUNER: return "FM tuner";
case AUDIO_SOURCE_HOTWORD: return "hotword";
default: return "unknown";
@@ -541,7 +549,8 @@
mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
// mName will be set by concrete (non-virtual) subclass
mDeathRecipient(new PMDeathRecipient(this)),
- mSystemReady(systemReady)
+ mSystemReady(systemReady),
+ mNotifiedBatteryStart(false)
{
memset(&mPatch, 0, sizeof(struct audio_patch));
}
@@ -662,7 +671,19 @@
// sendSetParameterConfigEvent_l() must be called with ThreadBase::mLock held
status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
{
- sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
+ sp<ConfigEvent> configEvent;
+ AudioParameter param(keyValuePair);
+ int value;
+ if (param.getInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), value) == NO_ERROR) {
+ setMasterMono_l(value != 0);
+ if (param.size() == 1) {
+ return NO_ERROR; // should be a solo parameter - we don't pass down
+ }
+ param.remove(String8(AUDIO_PARAMETER_MONO_OUTPUT));
+ configEvent = new SetParameterConfigEvent(param.toString());
+ } else {
+ configEvent = new SetParameterConfigEvent(keyValuePair);
+ }
return sendConfigEvent_l(configEvent);
}
@@ -832,8 +853,8 @@
dprintf(fd, " Channel count: %u\n", mChannelCount);
dprintf(fd, " Channel mask: 0x%08x (%s)\n", mChannelMask,
channelMaskToString(mChannelMask, mType != RECORD).string());
- dprintf(fd, " Format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
- dprintf(fd, " Frame size: %zu bytes\n", mFrameSize);
+ dprintf(fd, " Processing format: 0x%x (%s)\n", mFormat, formatToString(mFormat));
+ dprintf(fd, " Processing frame size: %zu bytes\n", mFrameSize);
dprintf(fd, " Pending config events:");
size_t numConfig = mConfigEvents.size();
if (numConfig) {
@@ -907,14 +928,14 @@
status = mPowerManager->acquireWakeLockWithUid(POWERMANAGER_PARTIAL_WAKE_LOCK,
binder,
getWakeLockTag(),
- String16("media"),
+ String16("audioserver"),
uid,
true /* FIXME force oneway contrary to .aidl */);
} else {
status = mPowerManager->acquireWakeLock(POWERMANAGER_PARTIAL_WAKE_LOCK,
binder,
getWakeLockTag(),
- String16("media"),
+ String16("audioserver"),
true /* FIXME force oneway contrary to .aidl */);
}
if (status == NO_ERROR) {
@@ -922,6 +943,11 @@
}
ALOGV("acquireWakeLock_l() %s status %d", mThreadName, status);
}
+
+ if (!mNotifiedBatteryStart) {
+ BatteryNotifier::getInstance().noteStartAudio();
+ mNotifiedBatteryStart = true;
+ }
}
void AudioFlinger::ThreadBase::releaseWakeLock()
@@ -940,6 +966,11 @@
}
mWakeLockToken.clear();
}
+
+ if (mNotifiedBatteryStart) {
+ BatteryNotifier::getInstance().noteStopAudio();
+ mNotifiedBatteryStart = false;
+ }
}
void AudioFlinger::ThreadBase::updateWakeLockUids(const SortedVector<int> &uids) {
@@ -963,8 +994,12 @@
void AudioFlinger::ThreadBase::updateWakeLockUids_l(const SortedVector<int> &uids) {
getPowerManager_l();
- if (mWakeLockToken == NULL) {
- ALOGE("no wake lock to update!");
+ if (mWakeLockToken == NULL) { // token may be NULL if AudioFlinger::systemReady() not called.
+ if (mSystemReady) {
+ ALOGE("no wake lock to update, but system ready!");
+ } else {
+ ALOGW("no wake lock to update, system not ready yet");
+ }
return;
}
if (mPowerManager != 0) {
@@ -1589,6 +1624,7 @@
dprintf(fd, " Mixer buffer: %p\n", mMixerBuffer);
dprintf(fd, " Effect buffer: %p\n", mEffectBuffer);
dprintf(fd, " Fast track availMask=%#x\n", mFastTrackAvailMask);
+ dprintf(fd, " Standby delay ns=%lld\n", (long long)mStandbyDelayNs);
AudioStreamOut *output = mOutput;
audio_output_flags_t flags = output != NULL ? output->flags : AUDIO_OUTPUT_FLAG_NONE;
String8 flagsAsString = outputFlagsToString(flags);
@@ -2513,7 +2549,8 @@
- mSinkBufferSize from frame count * frame size
- mActiveSleepTimeUs from activeSleepTimeUs()
- mIdleSleepTimeUs from idleSleepTimeUs()
- - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only)
+ - mStandbyDelayNs from mActiveSleepTimeUs (DIRECT only) or forced to at least
+ kDefaultStandbyTimeInNsecs when connected to an A2DP device.
- maxPeriod from frame count and sample rate (MIXER only)
The parameters that affect these derived values are:
@@ -2532,6 +2569,15 @@
mSinkBufferSize = mNormalFrameCount * mFrameSize;
mActiveSleepTimeUs = activeSleepTimeUs();
mIdleSleepTimeUs = idleSleepTimeUs();
+
+ // make sure standby delay is not too short when connected to an A2DP sink to avoid
+ // truncating audio when going to standby.
+ mStandbyDelayNs = AudioFlinger::mStandbyTimeInNsecs;
+ if ((mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != 0) {
+ if (mStandbyDelayNs < kDefaultStandbyTimeInNsecs) {
+ mStandbyDelayNs = kDefaultStandbyTimeInNsecs;
+ }
+ }
}
void AudioFlinger::PlaybackThread::invalidateTracks(audio_stream_type_t streamType)
@@ -2543,7 +2589,7 @@
size_t size = mTracks.size();
for (size_t i = 0; i < size; i++) {
sp<Track> t = mTracks[i];
- if (t->streamType() == streamType) {
+ if (t->streamType() == streamType && t->isExternalTrack()) {
t->invalidate();
}
}
@@ -2882,6 +2928,13 @@
void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
+ // mono blend occurs for mixer threads only (not direct or offloaded)
+ // and is handled here if we're going directly to the sink.
+ if (requireMonoBlend() && !mEffectBufferValid) {
+ mono_blend(
+ mMixerBuffer, mMixerBufferFormat, mChannelCount, mNormalFrameCount);
+ }
+
memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
mNormalFrameCount * mChannelCount);
}
@@ -2917,6 +2970,11 @@
// TODO use mSleepTimeUs == 0 as an additional condition.
if (mEffectBufferValid) {
//ALOGV("writing effect buffer to sink buffer format %#x", mFormat);
+
+ if (requireMonoBlend()) {
+ mono_blend(mEffectBuffer, mEffectBufferFormat, mChannelCount, mNormalFrameCount);
+ }
+
memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
mNormalFrameCount * mChannelCount);
}
@@ -3259,7 +3317,8 @@
: PlaybackThread(audioFlinger, output, id, device, type, systemReady),
// mAudioMixer below
// mFastMixer below
- mFastMixerFutex(0)
+ mFastMixerFutex(0),
+ mMasterMono(false)
// mOutputSink below
// mPipeSink below
// mNormalSink below
@@ -3838,7 +3897,10 @@
// because we're about to decrement the last sp<> on those tracks.
block = FastMixerStateQueue::BLOCK_UNTIL_ACKED;
} else {
- LOG_ALWAYS_FATAL("fast track %d should have been active", j);
+ LOG_ALWAYS_FATAL("fast track %d should have been active; "
+ "mState=%d, mTrackMask=%#x, recentUnderruns=%u, isShared=%d",
+ j, track->mState, state->mTrackMask, recentUnderruns,
+ track->sharedBuffer() != 0);
}
tracksToRemove->add(track);
// Avoids a misleading display in dumpsys
@@ -4248,6 +4310,7 @@
status_t& status)
{
bool reconfig = false;
+ bool a2dpDeviceChanged = false;
status = NO_ERROR;
@@ -4324,6 +4387,8 @@
// forward device change to effects that have requested to be
// aware of attached audio device.
if (value != AUDIO_DEVICE_NONE) {
+ a2dpDeviceChanged =
+ (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
mOutDevice = value;
for (size_t i = 0; i < mEffectChains.size(); i++) {
mEffectChains[i]->setDevice_l(mOutDevice);
@@ -4367,7 +4432,7 @@
sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
}
- return reconfig;
+ return reconfig || a2dpDeviceChanged;
}
@@ -4380,10 +4445,15 @@
PlaybackThread::dumpInternals(fd, args);
dprintf(fd, " Thread throttle time (msecs): %u\n", mThreadThrottleTimeMs);
dprintf(fd, " AudioMixer tracks: 0x%08x\n", mAudioMixer->trackNames());
+ dprintf(fd, " Master mono: %s\n", mMasterMono ? "on" : "off");
// Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- const FastMixerDumpState copy(mFastMixerDumpState);
- copy.dump(fd);
+ // 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 FastMixerDumpState *copy = new FastMixerDumpState(mFastMixerDumpState);
+ copy->dump(fd);
+ delete copy;
#ifdef STATE_QUEUE_DUMP
// Similar for state queue
@@ -4803,6 +4873,7 @@
status_t& status)
{
bool reconfig = false;
+ bool a2dpDeviceChanged = false;
status = NO_ERROR;
@@ -4812,6 +4883,8 @@
// forward device change to effects that have requested to be
// aware of attached audio device.
if (value != AUDIO_DEVICE_NONE) {
+ a2dpDeviceChanged =
+ (mOutDevice & AUDIO_DEVICE_OUT_ALL_A2DP) != (value & AUDIO_DEVICE_OUT_ALL_A2DP);
mOutDevice = value;
for (size_t i = 0; i < mEffectChains.size(); i++) {
mEffectChains[i]->setDevice_l(mOutDevice);
@@ -4844,7 +4917,7 @@
}
}
- return reconfig;
+ return reconfig || a2dpDeviceChanged;
}
uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs() const
@@ -6356,9 +6429,13 @@
dprintf(fd, " Fast capture thread: %s\n", hasFastCapture() ? "yes" : "no");
dprintf(fd, " Fast track available: %s\n", mFastTrackAvail ? "yes" : "no");
- // Make a non-atomic copy of fast capture dump state so it won't change underneath us
- const FastCaptureDumpState copy(mFastCaptureDumpState);
- copy.dump(fd);
+ // Make a non-atomic copy of fast capture 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 FastCaptureDumpState *copy = new FastCaptureDumpState(mFastCaptureDumpState);
+ copy->dump(fd);
+ delete copy;
}
void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args __unused)
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 46ac300..8eed50d 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -400,6 +400,8 @@
String16 getWakeLockTag();
virtual void preExit() { }
+ virtual void setMasterMono_l(bool mono __unused) { }
+ virtual bool requireMonoBlend() { return false; }
friend class AudioFlinger; // for mEffectChains
@@ -457,6 +459,7 @@
static const size_t kLogSize = 4 * 1024;
sp<NBLog::Writer> mNBLogWriter;
bool mSystemReady;
+ bool mNotifiedBatteryStart;
};
// --- PlaybackThread ---
@@ -908,6 +911,7 @@
// mFastMixer->sq() // for mutating and pushing state
int32_t mFastMixerFutex; // for cold idle
+ std::atomic_bool mMasterMono;
public:
virtual bool hasFastMixer() const { return mFastMixer != 0; }
virtual FastTrackUnderruns getFastTrackUnderruns(size_t fastIndex) const {
@@ -915,6 +919,15 @@
return mFastMixerDumpState.mTracks[fastIndex].mUnderruns;
}
+protected:
+ virtual void setMasterMono_l(bool mono) {
+ mMasterMono.store(mono);
+ if (mFastMixer != nullptr) { /* hasFastMixer() */
+ mFastMixer->setMasterMono(mMasterMono);
+ }
+ }
+ // the FastMixer performs mono blend if it exists.
+ virtual bool requireMonoBlend() { return mMasterMono.load() && !hasFastMixer(); }
};
class DirectOutputThread : public PlaybackThread {
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 0e24b52..b1638ea 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -100,13 +100,11 @@
mType(type),
mThreadIoHandle(thread->id())
{
- // if the caller is us, trust the specified uid
- if (IPCThreadState::self()->getCallingPid() != getpid_cached || clientUid == -1) {
- int newclientUid = IPCThreadState::self()->getCallingUid();
- if (clientUid != -1 && clientUid != newclientUid) {
- ALOGW("uid %d tried to pass itself off as %d", newclientUid, clientUid);
- }
- clientUid = newclientUid;
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid) || clientUid == -1) {
+ ALOGW_IF(clientUid != -1 && clientUid != (int)callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, clientUid);
+ clientUid = (int)callingUid;
}
// clientUid contains the uid of the app that is responsible for this track, so we can blame
// battery usage on it.
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index 5b38e1c..671d7fb 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -24,6 +24,7 @@
$(call include-path-for, audio-utils) \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include \
$(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+ $(TOPDIR)frameworks/av/services/audiopolicy/utilities \
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -84,6 +85,7 @@
LOCAL_C_INCLUDES += \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include \
$(TOPDIR)frameworks/av/services/audiopolicy/engine/interface \
+ $(TOPDIR)frameworks/av/services/audiopolicy/utilities \
LOCAL_STATIC_LIBRARIES := \
libmedia_helper \
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index c1e7bc0..dd3f144 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -225,8 +225,12 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle) = 0;
+ audio_io_handle_t *handle,
+ uid_t uid) = 0;
virtual status_t stopAudioSource(audio_io_handle_t handle) = 0;
+
+ virtual status_t setMasterMono(bool mono) = 0;
+ virtual status_t getMasterMono(bool *mono) = 0;
};
@@ -331,6 +335,9 @@
virtual audio_unique_id_t newAudioUniqueId() = 0;
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state) = 0;
+
+ virtual void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source) = 0;
};
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface);
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index 712f7a7..d091179 100755
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -30,6 +30,17 @@
float mDBAttenuation;
};
+/**
+ * device categories used for volume curve management.
+ */
+enum device_category {
+ DEVICE_CATEGORY_HEADSET,
+ DEVICE_CATEGORY_SPEAKER,
+ DEVICE_CATEGORY_EARPIECE,
+ DEVICE_CATEGORY_EXT_MEDIA,
+ DEVICE_CATEGORY_CNT
+};
+
class Volume
{
public:
@@ -50,17 +61,6 @@
};
/**
- * device categories used for volume curve management.
- */
- enum device_category {
- DEVICE_CATEGORY_HEADSET,
- DEVICE_CATEGORY_SPEAKER,
- DEVICE_CATEGORY_EARPIECE,
- DEVICE_CATEGORY_EXT_MEDIA,
- DEVICE_CATEGORY_CNT
- };
-
- /**
* extract one device relevant for volume control from multiple device selection
*
* @param[in] device for which the volume category is associated
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index 4b73e3c..34984f9 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -18,6 +18,8 @@
#include <system/audio.h>
+static const audio_format_t gDynamicFormat = AUDIO_FORMAT_DEFAULT;
+
// For mixed output and inputs, the policy will use max mixer sampling rates.
// Do not limit sampling rate otherwise
#define MAX_MIXER_SAMPLING_RATE 192000
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 8728ff3..0c28fc9 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -9,14 +9,20 @@
src/HwModule.cpp \
src/IOProfile.cpp \
src/AudioPort.cpp \
+ src/AudioProfile.cpp \
+ src/AudioRoute.cpp \
src/AudioPolicyMix.cpp \
src/AudioPatch.cpp \
src/AudioInputDescriptor.cpp \
src/AudioOutputDescriptor.cpp \
+ src/AudioCollections.cpp \
src/EffectDescriptor.cpp \
src/ConfigParsingUtils.cpp \
src/SoundTriggerSession.cpp \
src/SessionRoute.cpp \
+ src/AudioSourceDescriptor.cpp \
+ src/TypeConverter.cpp \
+ src/AudioSession.cpp
LOCAL_SHARED_LIBRARIES := \
libcutils \
@@ -26,7 +32,8 @@
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include \
$(TOPDIR)frameworks/av/services/audiopolicy/common/include \
- $(TOPDIR)frameworks/av/services/audiopolicy
+ $(TOPDIR)frameworks/av/services/audiopolicy \
+ $(TOPDIR)frameworks/av/services/audiopolicy/utilities \
LOCAL_EXPORT_C_INCLUDE_DIRS := \
$(LOCAL_PATH)/include
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
new file mode 100644
index 0000000..814c5c2
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -0,0 +1,44 @@
+/*
+ * 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 <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+class AudioPort;
+class AudioRoute;
+
+class AudioPortVector : public Vector<sp<AudioPort> >
+{
+public:
+ sp<AudioPort> findByTagName(const String8 &tagName) const;
+};
+
+
+class AudioRouteVector : public Vector<sp<AudioRoute> >
+{
+public:
+ status_t dump(int fd) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
index 21fbf9b..cea5c0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -28,10 +28,39 @@
AudioGain(int index, bool useInChannelMask);
virtual ~AudioGain() {}
+ void setMode(audio_gain_mode_t mode) { mGain.mode = mode; }
+ const audio_gain_mode_t &getMode() const { return mGain.mode; }
+
+ void setChannelMask(audio_channel_mask_t mask) { mGain.channel_mask = mask; }
+ const audio_channel_mask_t &getChannelMask() const { return mGain.channel_mask; }
+
+ void setMinValueInMb(int minValue) { mGain.min_value = minValue; }
+ int getMinValueInMb() const { return mGain.min_value; }
+
+ void setMaxValueInMb(int maxValue) { mGain.max_value = maxValue; }
+ int getMaxValueInMb() const { return mGain.max_value; }
+
+ void setDefaultValueInMb(int defaultValue) { mGain.default_value = defaultValue; }
+ int getDefaultValueInMb() const { return mGain.default_value; }
+
+ void setStepValueInMb(uint32_t stepValue) { mGain.step_value = stepValue; }
+ int getStepValueInMb() const { return mGain.step_value; }
+
+ void setMinRampInMs(uint32_t minRamp) { mGain.min_ramp_ms = minRamp; }
+ int getMinRampInMs() const { return mGain.min_ramp_ms; }
+
+ void setMaxRampInMs(uint32_t maxRamp) { mGain.max_ramp_ms = maxRamp; }
+ int getMaxRampInMs() const { return mGain.max_ramp_ms; }
+
+ // TODO: remove dump from here (split serialization)
void dump(int fd, int spaces, int index) const;
void getDefaultConfig(struct audio_gain_config *config);
status_t checkConfig(const struct audio_gain_config *config);
+
+ const struct audio_gain &getGain() const { return mGain; }
+
+private:
int mIndex;
struct audio_gain mGain;
bool mUseInChannelMask;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 48d09ed..77c0d07 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -17,6 +17,7 @@
#pragma once
#include "AudioPort.h"
+#include "AudioSession.h"
#include <utils/Errors.h>
#include <system/audio.h>
#include <utils/SortedVector.h>
@@ -36,6 +37,7 @@
void setIoHandle(audio_io_handle_t ioHandle);
audio_port_handle_t getId() const;
audio_module_handle_t getModuleHandle() const;
+ uint32_t getOpenRefCount() const;
status_t dump(int fd);
@@ -43,14 +45,7 @@
audio_devices_t mDevice; // current device this input is routed to
AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
audio_patch_handle_t mPatchHandle;
- uint32_t mRefCount; // number of AudioRecord clients using
- // this input
- uint32_t mOpenRefCount;
- audio_source_t mInputSource; // input source selected by application
- //(mediarecorder.h)
const sp<IOProfile> mProfile; // I/O profile this output derives from
- SortedVector<audio_session_t> mSessions; // audio sessions attached to this input
- bool mIsSoundTrigger; // used by a soundtrigger capture
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
@@ -60,17 +55,27 @@
SortedVector<audio_session_t> getPreemptedSessions() const;
bool hasPreemptedSession(audio_session_t session) const;
void clearPreemptedSessions();
+ bool isActive() const;
+ bool isSourceActive(audio_source_t source) const;
+ audio_source_t inputSource() const;
+ bool isSoundTrigger() const;
+ status_t addAudioSession(audio_session_t session,
+ const sp<AudioSession>& audioSession);
+ status_t removeAudioSession(audio_session_t session);
+ sp<AudioSession> getAudioSession(audio_session_t session) const;
+ AudioSessionCollection getActiveAudioSessions() const;
private:
audio_port_handle_t mId;
- // Because a preemtible capture session can preempt another one, we end up in an endless loop
+ // audio sessions attached to this input
+ AudioSessionCollection mSessions;
+ // Because a preemptible capture session can preempt another one, we end up in an endless loop
// situation were each session is allowed to restart after being preempted,
// thus preempting the other one which restarts and so on.
// To avoid this situation, we store which audio session was preempted when
// a particular input started and prevent preemption of this active input by this session.
// We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
SortedVector<audio_session_t> mPreemptedSessions;
-
};
class AudioInputCollection :
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 50f622d..f8439be 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -22,12 +22,14 @@
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
+#include "AudioSourceDescriptor.h"
namespace android {
class IOProfile;
class AudioMix;
class AudioPolicyClientInterface;
+class DeviceDescriptor;
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
@@ -126,6 +128,31 @@
uint32_t mGlobalRefCount; // non-stream-specific ref count
};
+// Audio output driven by an input device directly.
+class HwAudioOutputDescriptor: public AudioOutputDescriptor
+{
+public:
+ HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ AudioPolicyClientInterface *clientInterface);
+ virtual ~HwAudioOutputDescriptor() {}
+
+ status_t dump(int fd);
+
+ virtual audio_devices_t supportedDevices();
+ virtual bool setVolume(float volume,
+ audio_stream_type_t stream,
+ audio_devices_t device,
+ uint32_t delayMs,
+ bool force);
+
+ virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig = NULL) const;
+ virtual void toAudioPort(struct audio_port *port) const;
+
+ const sp<AudioSourceDescriptor> mSource;
+
+};
+
class SwAudioOutputCollection :
public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> >
{
@@ -160,4 +187,19 @@
status_t dump(int fd) const;
};
+class HwAudioOutputCollection :
+ public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> >
+{
+public:
+ bool isStreamActive(audio_stream_type_t stream, uint32_t inPastMs = 0) const;
+
+ /**
+ * return true if any output is playing anything besides the stream to ignore
+ */
+ bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
+
+ status_t dump(int fd) const;
+};
+
+
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
new file mode 100644
index 0000000..20c0e36
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009 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 <AudioGain.h>
+#include <AudioPort.h>
+#include <AudioPatch.h>
+#include <DeviceDescriptor.h>
+#include <IOProfile.h>
+#include <HwModule.h>
+#include <AudioInputDescriptor.h>
+#include <AudioOutputDescriptor.h>
+#include <AudioPolicyMix.h>
+#include <EffectDescriptor.h>
+#include <SoundTriggerSession.h>
+#include <StreamDescriptor.h>
+#include <SessionRoute.h>
+
+namespace android {
+
+class AudioPolicyConfig
+{
+public:
+ AudioPolicyConfig(HwModuleCollection &hwModules,
+ DeviceVector &availableOutputDevices,
+ DeviceVector &availableInputDevices,
+ sp<DeviceDescriptor> &defaultOutputDevices,
+ bool &isSpeakerDrcEnabled)
+ : mHwModules(hwModules),
+ mAvailableOutputDevices(availableOutputDevices),
+ mAvailableInputDevices(availableInputDevices),
+ mDefaultOutputDevices(defaultOutputDevices),
+ mIsSpeakerDrcEnabled(isSpeakerDrcEnabled)
+ {}
+
+ void setHwModules(const HwModuleCollection &hwModules)
+ {
+ mHwModules = hwModules;
+ }
+
+ void addAvailableInputDevices(const DeviceVector &availableInputDevices)
+ {
+ mAvailableInputDevices.add(availableInputDevices);
+ }
+
+ void addAvailableOutputDevices(const DeviceVector &availableOutputDevices)
+ {
+ mAvailableOutputDevices.add(availableOutputDevices);
+ }
+
+ void setSpeakerDrcEnabled(bool isSpeakerDrcEnabled)
+ {
+ mIsSpeakerDrcEnabled = isSpeakerDrcEnabled;
+ }
+
+ const HwModuleCollection getHwModules() const { return mHwModules; }
+
+ const DeviceVector &getAvailableInputDevices() const
+ {
+ return mAvailableInputDevices;
+ }
+
+ const DeviceVector &getAvailableOutputDevices() const
+ {
+ return mAvailableOutputDevices;
+ }
+
+ void setDefaultOutputDevice(const sp<DeviceDescriptor> &defaultDevice)
+ {
+ mDefaultOutputDevices = defaultDevice;
+ }
+
+ const sp<DeviceDescriptor> &getDefaultOutputDevice() const { return mDefaultOutputDevices; }
+
+ void setDefault(void)
+ {
+ mDefaultOutputDevices = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
+ sp<HwModule> module;
+ sp<DeviceDescriptor> defaultInputDevice = new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
+ mAvailableOutputDevices.add(mDefaultOutputDevices);
+ mAvailableInputDevices.add(defaultInputDevice);
+
+ module = new HwModule("primary");
+
+ sp<OutputProfile> outProfile;
+ outProfile = new OutputProfile(String8("primary"));
+ outProfile->attach(module);
+ outProfile->addAudioProfile(
+ new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 44100));
+ outProfile->addSupportedDevice(mDefaultOutputDevices);
+ outProfile->setFlags(AUDIO_OUTPUT_FLAG_PRIMARY);
+ module->mOutputProfiles.add(outProfile);
+
+ sp<InputProfile> inProfile;
+ inProfile = new InputProfile(String8("primary"));
+ inProfile->attach(module);
+ inProfile->addAudioProfile(
+ new AudioProfile(AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_IN_MONO, 8000));
+ inProfile->addSupportedDevice(defaultInputDevice);
+ module->mInputProfiles.add(inProfile);
+
+ mHwModules.add(module);
+ }
+
+private:
+ HwModuleCollection &mHwModules; /**< Collection of Module, with Profiles, i.e. Mix Ports. */
+ DeviceVector &mAvailableOutputDevices;
+ DeviceVector &mAvailableInputDevices;
+ sp<DeviceDescriptor> &mDefaultOutputDevices;
+ bool &mIsSpeakerDrcEnabled;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index 4fdf5b4..12e42ea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -16,6 +16,8 @@
#pragma once
+#include "AudioCollections.h"
+#include "AudioProfile.h"
#include <utils/String8.h>
#include <utils/Vector.h>
#include <utils/RefBase.h>
@@ -27,14 +29,31 @@
class HwModule;
class AudioGain;
+class AudioRoute;
+typedef Vector<sp<AudioGain> > AudioGainCollection;
class AudioPort : public virtual RefBase
{
public:
- AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role);
+ AudioPort(const String8& name, audio_port_type_t type, audio_port_role_t role) :
+ mName(name), mType(type), mRole(role), mFlags(AUDIO_OUTPUT_FLAG_NONE) {}
+
virtual ~AudioPort() {}
+ void setName(const String8 &name) { mName = name; }
+ const String8 &getName() const { return mName; }
+
+ audio_port_type_t getType() const { return mType; }
+ audio_port_role_t getRole() const { return mRole; }
+
+ virtual const String8 getTagName() const = 0;
+
+ void setGains(const AudioGainCollection &gains) { mGains = gains; }
+ const AudioGainCollection &getGains() const { return mGains; }
+
+ void setFlags(uint32_t flags) { mFlags = flags; }
+ uint32_t getFlags() const { return mFlags; }
+
virtual void attach(const sp<HwModule>& module);
bool isAttached() { return mModule != 0; }
@@ -43,66 +62,81 @@
virtual void toAudioPort(struct audio_port *port) const;
virtual void importAudioPort(const sp<AudioPort> port);
- void clearCapabilities();
+ void clearCapabilities() { mProfiles.clearProfiles(); }
- void loadSamplingRates(char *name);
- void loadFormats(char *name);
- void loadOutChannels(char *name);
- void loadInChannels(char *name);
+ void addAudioProfile(const sp<AudioProfile> &profile) { mProfiles.add(profile); }
- audio_gain_mode_t loadGainMode(char *name);
- void loadGain(cnode *root, int index);
- virtual void loadGains(cnode *root);
+ void setAudioProfiles(const AudioProfileVector &profiles) { mProfiles = profiles; }
+ AudioProfileVector &getAudioProfiles() { return mProfiles; }
+
+ bool hasValidAudioProfile() const { return mProfiles.hasValidProfile(); }
+
+ bool hasDynamicAudioProfile() const { return mProfiles.hasDynamicProfile(); }
// searches for an exact match
- status_t checkExactSamplingRate(uint32_t samplingRate) const;
- // searches for a compatible match, and returns the best match via updatedSamplingRate
- status_t checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t *updatedSamplingRate) const;
- // searches for an exact match
- status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
- // searches for a compatible match, currently implemented for input channel masks only
- status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask) const;
+ status_t checkExactAudioProfile(uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) const
+ {
+ return mProfiles.checkExactProfile(samplingRate, channelMask, format);
+ }
- status_t checkExactFormat(audio_format_t format) const;
- // searches for a compatible match, currently implemented for input formats only
- status_t checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat) const;
+ // searches for a compatible match, currently implemented for input
+ // parameters are input|output, returned value is the best match.
+ status_t checkCompatibleAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
+ {
+ return mProfiles.checkCompatibleProfile(samplingRate, channelMask, format, mType, mRole);
+ }
+
+ void clearAudioProfiles() { return mProfiles.clearProfiles(); }
+
status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;
- uint32_t pickSamplingRate() const;
- audio_channel_mask_t pickChannelMask() const;
- audio_format_t pickFormat() const;
+ void pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const;
static const audio_format_t sPcmFormatCompareTable[];
- static int compareFormats(const audio_format_t *format1, const audio_format_t *format2) {
- return compareFormats(*format1, *format2);
- }
+
static int compareFormats(audio_format_t format1, audio_format_t format2);
audio_module_handle_t getModuleHandle() const;
uint32_t getModuleVersion() const;
const char *getModuleName() const;
- void dump(int fd, int spaces) const;
+ bool useInputChannelMask() const
+ {
+ return ((mType == AUDIO_PORT_TYPE_DEVICE) && (mRole == AUDIO_PORT_ROLE_SOURCE)) ||
+ ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SINK));
+ }
+
+ inline bool isDirectOutput() const
+ {
+ return (mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
+ (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD));
+ }
+
+ void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
+ const AudioRouteVector &getRoutes() const { return mRoutes; }
+
+ void dump(int fd, int spaces, bool verbose = true) const;
void log(const char* indent) const;
- String8 mName;
- audio_port_type_t mType;
- audio_port_role_t mRole;
- bool mUseInChannelMask;
- // by convention, "0' in the first entry in mSamplingRates, mChannelMasks or mFormats
- // indicates the supported parameters should be read from the output stream
- // after it is opened for the first time
- Vector <uint32_t> mSamplingRates; // supported sampling rates
- Vector <audio_channel_mask_t> mChannelMasks; // supported channel masks
- Vector <audio_format_t> mFormats; // supported audio formats
- Vector < sp<AudioGain> > mGains; // gain controllers
+ AudioGainCollection mGains; // gain controllers
sp<HwModule> mModule; // audio HW module exposing this I/O stream
- uint32_t mFlags; // attribute flags (e.g primary output,
- // direct output...).
private:
+ void pickChannelMask(audio_channel_mask_t &channelMask, const ChannelsVector &channelMasks) const;
+ void pickSamplingRate(uint32_t &rate,const SampleRateVector &samplingRates) const;
+
+ String8 mName;
+ audio_port_type_t mType;
+ audio_port_role_t mRole;
+ uint32_t mFlags; // attribute flags mask (e.g primary output, direct output...).
+ AudioProfileVector mProfiles; // AudioProfiles supported by this port (format, Rates, Channels)
+ AudioRouteVector mRoutes; // Routes involving this port
static volatile int32_t mNextUniqueId;
};
@@ -113,9 +147,9 @@
virtual ~AudioPortConfig() {}
status_t applyAudioPortConfig(const struct audio_port_config *config,
- struct audio_port_config *backupConfig = NULL);
+ struct audio_port_config *backupConfig = NULL);
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
- const struct audio_port_config *srcConfig = NULL) const = 0;
+ const struct audio_port_config *srcConfig = NULL) const = 0;
virtual sp<AudioPort> getAudioPort() const = 0;
uint32_t mSamplingRate;
audio_format_t mFormat;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
new file mode 100644
index 0000000..9780dc6
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -0,0 +1,353 @@
+/*
+ * 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 "policy.h"
+#include <utils/String8.h>
+#include <utils/SortedVector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <system/audio.h>
+#include <cutils/config_utils.h>
+
+namespace android {
+
+typedef SortedVector<uint32_t> SampleRateVector;
+typedef SortedVector<audio_channel_mask_t> ChannelsVector;
+typedef Vector<audio_format_t> FormatVector;
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right);
+
+class AudioProfile : public virtual RefBase
+{
+public:
+ 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,
+ const ChannelsVector &channelMasks,
+ const SampleRateVector &samplingRateCollection) :
+ mName(String8("")),
+ mFormat(format),
+ mChannelMasks(channelMasks),
+ mSamplingRates(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; }
+
+ 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
+ {
+ return mChannelMasks.indexOf(channels) >= 0;
+ }
+ inline 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;
+
+ bool hasValidFormat() const { return mFormat != AUDIO_FORMAT_DEFAULT; }
+ bool hasValidRates() const { return !mSamplingRates.isEmpty(); }
+ bool hasValidChannels() const { return !mChannelMasks.isEmpty(); }
+
+ void setDynamicChannels(bool dynamic) { mIsDynamicChannels = dynamic; }
+ bool isDynamicChannels() const { return mIsDynamicChannels; }
+
+ void setDynamicRate(bool dynamic) { mIsDynamicRate = dynamic; }
+ bool isDynamicRate() const { return mIsDynamicRate; }
+
+ void setDynamicFormat(bool dynamic) { mIsDynamicFormat = dynamic; }
+ bool isDynamicFormat() const { return mIsDynamicFormat; }
+
+ bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
+
+ void dump(int fd, int spaces) const;
+
+private:
+ String8 mName;
+ audio_format_t mFormat;
+ ChannelsVector mChannelMasks;
+ SampleRateVector mSamplingRates;
+
+ bool mIsDynamicFormat = false;
+ bool mIsDynamicChannels = false;
+ bool mIsDynamicRate = false;
+};
+
+
+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;
+ }
+
+ // 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;
+ }
+
+ bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+
+ 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;
+
+ FormatVector getSupportedFormats() const
+ {
+ FormatVector supportedFormats;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->hasValidFormat()) {
+ supportedFormats.add(itemAt(i)->getFormat());
+ }
+ }
+ return supportedFormats;
+ }
+
+ 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;
+ }
+
+ // 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;
+ }
+ clearProfiles();
+ 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 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;
+ }
+ }
+ }
+
+ 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);
+ }
+ }
+
+private:
+ 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;
+ }
+
+ static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
+};
+
+bool operator == (const AudioProfile &left, const AudioProfile &right);
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
new file mode 100644
index 0000000..67e197f
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -0,0 +1,58 @@
+/*
+ * 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 "AudioCollections.h"
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+
+namespace android
+{
+
+class AudioPort;
+class DeviceDescriptor;
+
+typedef enum {
+ AUDIO_ROUTE_MUX = 0,
+ AUDIO_ROUTE_MIX = 1
+} audio_route_type_t;
+
+class AudioRoute : public virtual RefBase
+{
+public:
+ AudioRoute(audio_route_type_t type) : mType(type) {}
+
+ void setSources(const AudioPortVector &sources) { mSources = sources; }
+ const AudioPortVector &getSources() const { return mSources; }
+
+ void setSink(const sp<AudioPort> &sink) { mSink = sink; }
+ const sp<AudioPort> &getSink() const { return mSink; }
+
+ audio_route_type_t getType() const { return mType; }
+
+ void dump(int fd, int spaces) const;
+
+private:
+ AudioPortVector mSources;
+ sp<AudioPort> mSink;
+ audio_route_type_t mType;
+
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSession.h b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
new file mode 100644
index 0000000..576822c
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSession.h
@@ -0,0 +1,94 @@
+/*
+ * 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/RefBase.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <media/AudioPolicy.h>
+
+namespace android {
+
+class AudioPolicyClientInterface;
+
+class AudioSession : public RefBase
+{
+public:
+ AudioSession(audio_session_t session,
+ audio_source_t inputSource,
+ audio_format_t format,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ uid_t uid,
+ bool isSoundTrigger,
+ AudioMix* policyMix,
+ AudioPolicyClientInterface *clientInterface);
+
+ status_t dump(int fd, int spaces, int index) const;
+
+ audio_session_t session() const { return mSession; }
+ audio_source_t inputSource()const { return mInputSource; }
+ audio_format_t format() const { return mFormat; }
+ uint32_t sampleRate() const { return mSampleRate; }
+ audio_channel_mask_t channelMask() const { return mChannelMask; }
+ audio_input_flags_t flags() const { return mFlags; }
+ uid_t uid() const { return mUid; }
+ bool matches(const sp<AudioSession> &other) const;
+ bool isSoundTrigger() const { return mIsSoundTrigger; }
+ uint32_t openCount() const { return mOpenCount; } ;
+ uint32_t activeCount() const { return mActiveCount; } ;
+
+ uint32_t changeOpenCount(int delta);
+ uint32_t changeActiveCount(int delta);
+
+private:
+ const audio_session_t mSession;
+ const audio_source_t mInputSource;
+ const audio_format_t mFormat;
+ const uint32_t mSampleRate;
+ const audio_channel_mask_t mChannelMask;
+ const audio_input_flags_t mFlags;
+ const uid_t mUid;
+ bool mIsSoundTrigger;
+ uint32_t mOpenCount;
+ uint32_t mActiveCount;
+ AudioMix* mPolicyMix; // non NULL when used by a dynamic policy
+ AudioPolicyClientInterface* mClientInterface;
+};
+
+class AudioSessionCollection :
+ public DefaultKeyedVector<audio_session_t, sp<AudioSession> >
+{
+public:
+ status_t addSession(audio_session_t session,
+ const sp<AudioSession>& audioSession);
+
+ status_t removeSession(audio_session_t session);
+
+ uint32_t getOpenCount() const;
+
+ AudioSessionCollection getActiveSessions() const;
+ bool hasActiveSession() const;
+ bool isSourceActive(audio_source_t source) const;
+
+ status_t dump(int fd, int spaces) const;
+};
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
new file mode 100644
index 0000000..7e1e24d
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
@@ -0,0 +1,59 @@
+/*
+ * 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/ConfigParsingUtils.h b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
index 78d2cdf..ab23105 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ConfigParsingUtils.h
@@ -16,6 +16,7 @@
#pragma once
+#include "AudioPolicyConfig.h"
#include "DeviceDescriptor.h"
#include "HwModule.h"
#include "audio_policy_conf.h"
@@ -33,243 +34,27 @@
// Definitions for audio_policy.conf file parsing
// ----------------------------------------------------------------------------
-struct StringToEnum {
- const char *name;
- uint32_t value;
-};
-
-// TODO: move to a separate file. Should be in sync with audio.h.
-#define STRING_TO_ENUM(string) { #string, (uint32_t)string } // uint32_t cast removes warning
-#define NAME_TO_ENUM(name, value) { name, value }
-#ifndef ARRAY_SIZE
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-#endif
-
-const StringToEnum sDeviceTypeToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_HDMI),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_LINE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_SPDIF),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_FM),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
- STRING_TO_ENUM(AUDIO_DEVICE_OUT_IP),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_AMBIENT),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_HDMI),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_LINE),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_SPDIF),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
- STRING_TO_ENUM(AUDIO_DEVICE_IN_IP),
-};
-
-const StringToEnum sDeviceNameToEnumTable[] = {
- NAME_TO_ENUM("Earpiece", AUDIO_DEVICE_OUT_EARPIECE),
- NAME_TO_ENUM("Speaker", AUDIO_DEVICE_OUT_SPEAKER),
- NAME_TO_ENUM("Speaker Protected", AUDIO_DEVICE_OUT_SPEAKER_SAFE),
- NAME_TO_ENUM("Wired Headset", AUDIO_DEVICE_OUT_WIRED_HEADSET),
- NAME_TO_ENUM("Wired Headphones", AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
- NAME_TO_ENUM("BT SCO", AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
- NAME_TO_ENUM("BT SCO Headset", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
- NAME_TO_ENUM("BT SCO Car Kit", AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
- NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_SCO),
- NAME_TO_ENUM("BT A2DP Out", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
- NAME_TO_ENUM("BT A2DP Headphones", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
- NAME_TO_ENUM("BT A2DP Speaker", AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
- NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_A2DP),
- NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_AUX_DIGITAL),
- NAME_TO_ENUM("HDMI Out", AUDIO_DEVICE_OUT_HDMI),
- NAME_TO_ENUM("Analog Dock Out", AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
- NAME_TO_ENUM("Digital Dock Out", AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
- NAME_TO_ENUM("USB Host Out", AUDIO_DEVICE_OUT_USB_ACCESSORY),
- NAME_TO_ENUM("USB Device Out", AUDIO_DEVICE_OUT_USB_DEVICE),
- NAME_TO_ENUM("", AUDIO_DEVICE_OUT_ALL_USB),
- NAME_TO_ENUM("Reroute Submix Out", AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
- NAME_TO_ENUM("Telephony Tx", AUDIO_DEVICE_OUT_TELEPHONY_TX),
- NAME_TO_ENUM("Line Out", AUDIO_DEVICE_OUT_LINE),
- NAME_TO_ENUM("HDMI ARC Out", AUDIO_DEVICE_OUT_HDMI_ARC),
- NAME_TO_ENUM("S/PDIF Out", AUDIO_DEVICE_OUT_SPDIF),
- NAME_TO_ENUM("FM transceiver Out", AUDIO_DEVICE_OUT_FM),
- NAME_TO_ENUM("Aux Line Out", AUDIO_DEVICE_OUT_AUX_LINE),
- NAME_TO_ENUM("IP Out", AUDIO_DEVICE_OUT_IP),
- NAME_TO_ENUM("Ambient Mic", AUDIO_DEVICE_IN_AMBIENT),
- NAME_TO_ENUM("Built-In Mic", AUDIO_DEVICE_IN_BUILTIN_MIC),
- NAME_TO_ENUM("BT SCO Headset Mic", AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
- NAME_TO_ENUM("", AUDIO_DEVICE_IN_ALL_SCO),
- NAME_TO_ENUM("Wired Headset Mic", AUDIO_DEVICE_IN_WIRED_HEADSET),
- NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_AUX_DIGITAL),
- NAME_TO_ENUM("HDMI In", AUDIO_DEVICE_IN_HDMI),
- NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_TELEPHONY_RX),
- NAME_TO_ENUM("Telephony Rx", AUDIO_DEVICE_IN_VOICE_CALL),
- NAME_TO_ENUM("Built-In Back Mic", AUDIO_DEVICE_IN_BACK_MIC),
- NAME_TO_ENUM("Reroute Submix In", AUDIO_DEVICE_IN_REMOTE_SUBMIX),
- NAME_TO_ENUM("Analog Dock In", AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
- NAME_TO_ENUM("Digital Dock In", AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
- NAME_TO_ENUM("USB Host In", AUDIO_DEVICE_IN_USB_ACCESSORY),
- NAME_TO_ENUM("USB Device In", AUDIO_DEVICE_IN_USB_DEVICE),
- NAME_TO_ENUM("FM Tuner In", AUDIO_DEVICE_IN_FM_TUNER),
- NAME_TO_ENUM("TV Tuner In", AUDIO_DEVICE_IN_TV_TUNER),
- NAME_TO_ENUM("Line In", AUDIO_DEVICE_IN_LINE),
- NAME_TO_ENUM("S/PDIF In", AUDIO_DEVICE_IN_SPDIF),
- NAME_TO_ENUM("BT A2DP In", AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
- NAME_TO_ENUM("Loopback In", AUDIO_DEVICE_IN_LOOPBACK),
- NAME_TO_ENUM("IP In", AUDIO_DEVICE_IN_IP),
-};
-
-const StringToEnum sOutputFlagNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_FAST),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_TTS),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_RAW),
- STRING_TO_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
-};
-
-const StringToEnum sInputFlagNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_FAST),
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_RAW),
- STRING_TO_ENUM(AUDIO_INPUT_FLAG_SYNC),
-};
-
-const StringToEnum sFormatNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_FLOAT),
- STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
- STRING_TO_ENUM(AUDIO_FORMAT_MP3),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_MAIN),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_LC),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_SSR),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_LTP),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V1),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_ERLC),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_LD),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_HE_V2),
- STRING_TO_ENUM(AUDIO_FORMAT_AAC_ELD),
- STRING_TO_ENUM(AUDIO_FORMAT_VORBIS),
- STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1),
- STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2),
- STRING_TO_ENUM(AUDIO_FORMAT_OPUS),
- STRING_TO_ENUM(AUDIO_FORMAT_AC3),
- STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
- STRING_TO_ENUM(AUDIO_FORMAT_DTS),
- STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
-};
-
-const StringToEnum sOutChannelsNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_MONO),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
-};
-
-const StringToEnum sInChannelsNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
- STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
- STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
-};
-
-const StringToEnum sIndexChannelsNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
- STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
-};
-
-const StringToEnum sGainModeNameToEnumTable[] = {
- STRING_TO_ENUM(AUDIO_GAIN_MODE_JOINT),
- STRING_TO_ENUM(AUDIO_GAIN_MODE_CHANNELS),
- STRING_TO_ENUM(AUDIO_GAIN_MODE_RAMP),
-};
-
class ConfigParsingUtils
{
public:
- static uint32_t stringToEnum(const struct StringToEnum *table,
- size_t size,
- const char *name);
- static const char *enumToString(const struct StringToEnum *table,
- size_t size,
- uint32_t value);
- static bool stringToBool(const char *value);
- static uint32_t parseOutputFlagNames(char *name);
- static uint32_t parseInputFlagNames(char *name);
- static audio_devices_t parseDeviceNames(char *name);
-
- static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
-
- static void loadGlobalConfig(cnode *root, const sp<HwModule>& module,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
-
- static status_t loadAudioPolicyConfig(const char *path,
- HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
+ static status_t loadConfig(const char *path, AudioPolicyConfig &config);
private:
- static void loadHwModule(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled);
+ static uint32_t parseOutputFlagNames(const char *name);
+ static void loadAudioPortGain(cnode *root, AudioPort &audioPort, int index);
+ static void loadAudioPortGains(cnode *root, AudioPort &audioPort);
+ static void loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc);
+ static status_t loadHwModuleDevice(cnode *root, DeviceVector &devices);
+ static status_t loadHwModuleProfile(cnode *root, sp<HwModule> &module, audio_port_role_t role);
+ static void loadDevicesFromTag(const char *tag, DeviceVector &devices,
+ const DeviceVector &declaredDevices);
+ static void loadHwModules(cnode *root, HwModuleCollection &hwModules,
+ AudioPolicyConfig &config);
+ static void loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
+ const sp<HwModule> &primaryModule);
+ static void loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
+ AudioPolicyConfig &config);
+ static status_t loadHwModule(cnode *root, sp<HwModule> &module, AudioPolicyConfig &config);
};
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c42ece6..54fcd0b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -29,10 +29,15 @@
class DeviceDescriptor : public AudioPort, public AudioPortConfig
{
public:
- DeviceDescriptor(audio_devices_t type);
+ // Note that empty name refers by convention to a generic device.
+ DeviceDescriptor(audio_devices_t type, const String8 &tagName = String8(""));
virtual ~DeviceDescriptor() {}
+ virtual const String8 getTagName() const { return mTagName; }
+
+ audio_devices_t type() const { return mDeviceType; }
+
bool equals(const sp<DeviceDescriptor>& other) const;
// AudioPortConfig
@@ -42,50 +47,46 @@
// AudioPort
virtual void attach(const sp<HwModule>& module);
- virtual void loadGains(cnode *root);
virtual void toAudioPort(struct audio_port *port) const;
virtual void importAudioPort(const sp<AudioPort> port);
audio_port_handle_t getId() const;
- audio_devices_t type() const { return mDeviceType; }
- status_t dump(int fd, int spaces, int index) const;
+ status_t dump(int fd, int spaces, int index, bool verbose = true) const;
void log() const;
- String8 mTag;
String8 mAddress;
private:
+ String8 mTagName; // Unique human readable identifier for a device port found in conf file.
audio_devices_t mDeviceType;
audio_port_handle_t mId;
friend class DeviceVector;
};
-class DeviceVector : public SortedVector< sp<DeviceDescriptor> >
+class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
{
public:
DeviceVector() : SortedVector(), mDeviceTypes(AUDIO_DEVICE_NONE) {}
ssize_t add(const sp<DeviceDescriptor>& item);
+ void add(const DeviceVector &devices);
ssize_t remove(const sp<DeviceDescriptor>& item);
ssize_t indexOf(const sp<DeviceDescriptor>& item) const;
audio_devices_t types() const { return mDeviceTypes; }
- void loadDevicesFromType(audio_devices_t types);
- void loadDevicesFromTag(char *tag, const DeviceVector& declaredDevices);
-
sp<DeviceDescriptor> getDevice(audio_devices_t type, String8 address) const;
DeviceVector getDevicesFromType(audio_devices_t types) const;
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
- sp<DeviceDescriptor> getDeviceFromTag(const String8& tag) const;
+ sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address) const;
audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
audio_policy_dev_state_t getDeviceConnectionState(const sp<DeviceDescriptor> &devDesc) const;
- status_t dump(int fd, const String8 &direction) const;
+ status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
private:
void refreshTypes();
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 92c3ea2..93d03e6 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -17,26 +17,54 @@
#pragma once
#include "DeviceDescriptor.h"
+#include "AudioRoute.h"
+#include <hardware/audio.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
#include <utils/Errors.h>
#include <utils/Vector.h>
#include <system/audio.h>
#include <cutils/config_utils.h>
+#include <string>
namespace android {
class IOProfile;
+class InputProfile;
+class OutputProfile;
+
+typedef Vector<sp<IOProfile> > InputProfileCollection;
+typedef Vector<sp<IOProfile> > OutputProfileCollection;
+typedef Vector<sp<IOProfile> > IOProfileCollection;
class HwModule : public RefBase
{
public:
- HwModule(const char *name);
+ HwModule(const char *name, uint32_t halVersion = AUDIO_DEVICE_API_VERSION_MIN);
~HwModule();
- status_t loadOutput(cnode *root);
- status_t loadInput(cnode *root);
- status_t loadDevice(cnode *root);
+ const char *getName() const { return mName.string(); }
+
+
+ const DeviceVector &getDeclaredDevices() const { return mDeclaredDevices; }
+ void setDeclaredDevices(const DeviceVector &devices);
+
+ const InputProfileCollection &getInputProfiles() const { return mInputProfiles; }
+
+ const OutputProfileCollection &getOutputProfiles() const { return mOutputProfiles; }
+
+ void setProfiles(const IOProfileCollection &profiles);
+
+ void setHalVersion(uint32_t halVersion) { mHalVersion = halVersion; }
+ uint32_t getHalVersion() const { return mHalVersion; }
+
+ sp<DeviceDescriptor> getRouteSinkDevice(const sp<AudioRoute> &route) const;
+ DeviceVector getRouteSourceDevices(const sp<AudioRoute> &route) const;
+ void setRoutes(const AudioRouteVector &routes);
+
+ status_t addOutputProfile(const sp<IOProfile> &profile);
+ status_t addInputProfile(const sp<IOProfile> &profile);
+ status_t addProfile(const sp<IOProfile> &profile);
status_t addOutputProfile(String8 name, const audio_config_t *config,
audio_devices_t device, String8 address);
@@ -47,26 +75,38 @@
audio_module_handle_t getHandle() const { return mHandle; }
+ sp<AudioPort> findPortByTagName(const String8 &tagName) const
+ {
+ return mPorts.findByTagName(tagName);
+ }
+
+ // TODO remove from here (split serialization)
void dump(int fd);
- const char *const mName; // base name of the audio HW module (primary, a2dp ...)
- uint32_t mHalVersion; // audio HAL API version
- audio_module_handle_t mHandle;
- Vector < sp<IOProfile> > mOutputProfiles; // output profiles exposed by this module
- Vector < sp<IOProfile> > mInputProfiles; // input profiles exposed by this module
- DeviceVector mDeclaredDevices; // devices declared in audio_policy.conf
+ const String8 mName; // base name of the audio HW module (primary, a2dp ...)
+ audio_module_handle_t mHandle;
+ OutputProfileCollection mOutputProfiles; // output profiles exposed by this module
+ InputProfileCollection mInputProfiles; // input profiles exposed by this module
+
+private:
+ void refreshSupportedDevices();
+
+ uint32_t mHalVersion; // audio HAL API version
+ DeviceVector mDeclaredDevices; // devices declared in audio_policy configuration file.
+ AudioRouteVector mRoutes;
+ AudioPortVector mPorts;
};
-class HwModuleCollection : public Vector< sp<HwModule> >
+class HwModuleCollection : public Vector<sp<HwModule> >
{
public:
sp<HwModule> getModuleFromName(const char *name) const;
- sp <HwModule> getModuleForDevice(audio_devices_t device) const;
+ sp<HwModule> getModuleForDevice(audio_devices_t device) const;
- sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
- const char *device_address,
- const char *device_name) const;
+ sp<DeviceDescriptor> getDeviceDescriptor(const audio_devices_t device,
+ const char *device_address,
+ const char *device_name) const;
status_t dump(int fd) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index ab6fcc1..eae9586 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -33,8 +33,11 @@
class IOProfile : public AudioPort
{
public:
- IOProfile(const String8& name, audio_port_role_t role);
- virtual ~IOProfile();
+ IOProfile(const String8 &name, audio_port_role_t role)
+ : AudioPort(name, AUDIO_PORT_TYPE_MIX, role) {}
+
+ // For a Profile aka MixPort, tag name and name are equivalent.
+ virtual const String8 getTagName() const { return getName(); }
// This method is used for both output and input.
// If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
@@ -53,8 +56,67 @@
void dump(int fd);
void log();
- DeviceVector mSupportedDevices; // supported devices
- // (devices this output can be routed to)
+ bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
+
+ bool supportDevice(audio_devices_t device) const
+ {
+ if (audio_is_output_devices(device)) {
+ return mSupportedDevices.types() & device;
+ }
+ return mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN);
+ }
+
+ bool supportDeviceAddress(const String8 &address) const
+ {
+ return mSupportedDevices[0]->mAddress == address;
+ }
+
+ // chose first device present in mSupportedDevices also part of deviceType
+ audio_devices_t getSupportedDeviceForType(audio_devices_t deviceType) const
+ {
+ for (size_t k = 0; k < mSupportedDevices.size(); k++) {
+ audio_devices_t profileType = mSupportedDevices[k]->type();
+ if (profileType & deviceType) {
+ return profileType;
+ }
+ }
+ return AUDIO_DEVICE_NONE;
+ }
+
+ audio_devices_t getSupportedDevicesType() const { return mSupportedDevices.types(); }
+
+ void clearSupportedDevices() { mSupportedDevices.clear(); }
+ void addSupportedDevice(const sp<DeviceDescriptor> &device)
+ {
+ mSupportedDevices.add(device);
+ }
+
+ void setSupportedDevices(const DeviceVector &devices)
+ {
+ mSupportedDevices = devices;
+ }
+
+ sp<DeviceDescriptor> getSupportedDeviceByAddress(audio_devices_t type, String8 address) const
+ {
+ return mSupportedDevices.getDevice(type, address);
+ }
+
+ const DeviceVector &getSupportedDevices() const { return mSupportedDevices; }
+
+private:
+ DeviceVector mSupportedDevices; // supported devices: this input/output can be routed from/to
+};
+
+class InputProfile : public IOProfile
+{
+public:
+ InputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SINK) {}
+};
+
+class OutputProfile : public IOProfile
+{
+public:
+ OutputProfile(const String8 &name) : IOProfile(name, AUDIO_PORT_ROLE_SOURCE) {}
};
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
index 84db5ab..fbc942c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/StreamDescriptor.h
@@ -41,14 +41,14 @@
void dump(int fd) const;
- void setVolumeCurvePoint(Volume::device_category deviceCategory, const VolumeCurvePoint *point);
- const VolumeCurvePoint *getVolumeCurvePoint(Volume::device_category deviceCategory) const
+ void setVolumeCurvePoint(device_category deviceCategory, const VolumeCurvePoint *point);
+ const VolumeCurvePoint *getVolumeCurvePoint(device_category deviceCategory) const
{
return mVolumeCurve[deviceCategory];
}
private:
- const VolumeCurvePoint *mVolumeCurve[Volume::DEVICE_CATEGORY_CNT];
+ const VolumeCurvePoint *mVolumeCurve[DEVICE_CATEGORY_CNT];
KeyedVector<audio_devices_t, int> mIndexCur; /**< current volume index per device. */
int mIndexMin; /**< min volume index. */
int mIndexMax; /**< max volume index. */
@@ -71,11 +71,11 @@
status_t dump(int fd) const;
void setVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory,
+ device_category deviceCategory,
const VolumeCurvePoint *point);
const VolumeCurvePoint *getVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory) const;
+ device_category deviceCategory) const;
void setVolumeIndexMin(audio_stream_type_t stream,int volIndexMin);
void setVolumeIndexMax(audio_stream_type_t stream,int volIndexMax);
diff --git a/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
new file mode 100644
index 0000000..14e2ecc
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/include/TypeConverter.h
@@ -0,0 +1,195 @@
+/*
+ * 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 "policy.h"
+#include <Volume.h>
+#include <system/audio.h>
+#include <convert/convert.h>
+#include <utils/Log.h>
+#include <string>
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+
+namespace android {
+
+struct SampleRateTraits
+{
+ typedef uint32_t Type;
+ typedef SortedVector<Type> Collection;
+};
+struct DeviceTraits
+{
+ typedef audio_devices_t Type;
+ typedef Vector<Type> Collection;
+};
+struct OutputFlagTraits
+{
+ typedef audio_output_flags_t Type;
+ typedef Vector<Type> Collection;
+};
+struct InputFlagTraits
+{
+ typedef audio_input_flags_t Type;
+ typedef Vector<Type> Collection;
+};
+struct FormatTraits
+{
+ typedef audio_format_t Type;
+ typedef Vector<Type> Collection;
+};
+struct ChannelTraits
+{
+ typedef audio_channel_mask_t Type;
+ typedef SortedVector<Type> Collection;
+};
+struct OutputChannelTraits : public ChannelTraits {};
+struct InputChannelTraits : public ChannelTraits {};
+struct ChannelIndexTraits : public ChannelTraits {};
+struct GainModeTraits
+{
+ typedef audio_gain_mode_t Type;
+ typedef Vector<Type> Collection;
+};
+struct StreamTraits
+{
+ typedef audio_stream_type_t Type;
+ typedef Vector<Type> Collection;
+};
+struct DeviceCategoryTraits
+{
+ typedef device_category Type;
+ typedef Vector<Type> Collection;
+};
+template <typename T>
+struct DefaultTraits
+{
+ typedef T Type;
+ typedef Vector<Type> Collection;
+};
+
+template <class Traits>
+static void collectionFromString(const std::string &str, typename Traits::Collection &collection,
+ const char *del = "|")
+{
+ char *literal = strdup(str.c_str());
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type value;
+ if (utilities::convertTo<std::string, typename Traits::Type >(cstr, value)) {
+ collection.add(value);
+ }
+ }
+ free(literal);
+}
+
+template <class Traits>
+class TypeConverter
+{
+public:
+ static bool toString(const typename Traits::Type &value, std::string &str);
+
+ static bool fromString(const std::string &str, typename Traits::Type &result);
+
+ static void collectionFromString(const std::string &str,
+ typename Traits::Collection &collection,
+ const char *del = "|");
+
+ static uint32_t maskFromString(const std::string &str, const char *del = "|");
+
+protected:
+ struct Table {
+ const char *literal;
+ typename Traits::Type value;
+ };
+
+ static const Table mTable[];
+ static const size_t mSize;
+};
+
+typedef TypeConverter<DeviceTraits> DeviceConverter;
+typedef TypeConverter<OutputFlagTraits> OutputFlagConverter;
+typedef TypeConverter<InputFlagTraits> InputFlagConverter;
+typedef TypeConverter<FormatTraits> FormatConverter;
+typedef TypeConverter<OutputChannelTraits> OutputChannelConverter;
+typedef TypeConverter<InputChannelTraits> InputChannelConverter;
+typedef TypeConverter<ChannelIndexTraits> ChannelIndexConverter;
+typedef TypeConverter<GainModeTraits> GainModeConverter;
+typedef TypeConverter<StreamTraits> StreamTypeConverter;
+typedef TypeConverter<DeviceCategoryTraits> DeviceCategoryConverter;
+
+static SampleRateTraits::Collection samplingRatesFromString(const std::string &samplingRates,
+ const char *del = "|")
+{
+ SampleRateTraits::Collection samplingRateCollection;
+ collectionFromString<SampleRateTraits>(samplingRates, samplingRateCollection, del);
+ return samplingRateCollection;
+}
+
+static FormatTraits::Collection formatsFromString(const std::string &formats, const char *del = "|")
+{
+ FormatTraits::Collection formatCollection;
+ FormatConverter::collectionFromString(formats, formatCollection, del);
+ return formatCollection;
+}
+
+static audio_format_t formatFromString(const std::string &literalFormat)
+{
+ audio_format_t format;
+ FormatConverter::fromString(literalFormat, format);
+ return format;
+}
+
+static audio_channel_mask_t channelMaskFromString(const std::string &literalChannels)
+{
+ audio_channel_mask_t channels;
+ if (!OutputChannelConverter::fromString(literalChannels, channels) ||
+ !InputChannelConverter::fromString(literalChannels, channels)) {
+ return AUDIO_CHANNEL_INVALID;
+ }
+ return channels;
+}
+
+static ChannelTraits::Collection channelMasksFromString(const std::string &channels,
+ const char *del = "|")
+{
+ ChannelTraits::Collection channelMaskCollection;
+ OutputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ InputChannelConverter::collectionFromString(channels, channelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(channels, channelMaskCollection, del);
+ return channelMaskCollection;
+}
+
+static InputChannelTraits::Collection inputChannelMasksFromString(const std::string &inChannels,
+ const char *del = "|")
+{
+ InputChannelTraits::Collection inputChannelMaskCollection;
+ InputChannelConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(inChannels, inputChannelMaskCollection, del);
+ return inputChannelMaskCollection;
+}
+
+static OutputChannelTraits::Collection outputChannelMasksFromString(const std::string &outChannels,
+ const char *del = "|")
+{
+ OutputChannelTraits::Collection outputChannelMaskCollection;
+ OutputChannelConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+ ChannelIndexConverter::collectionFromString(outChannels, outputChannelMaskCollection, del);
+ return outputChannelMaskCollection;
+}
+
+}; // namespace android
+
diff --git a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
index a393e3b..0a27947 100644
--- a/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
+++ b/services/audiopolicy/common/managerdefinitions/include/audio_policy_conf.h
@@ -47,10 +47,6 @@
#define DEVICES_TAG "devices"
#define FLAGS_TAG "flags"
-#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
- // "formats" in outputs descriptors indicating that supported
- // values should be queried after opening the output.
-
#define APM_DEVICES_TAG "devices"
#define APM_DEVICE_TYPE "type"
#define APM_DEVICE_ADDRESS "address"
@@ -69,3 +65,7 @@
#define GAIN_STEP_VALUE "step_value_mB"
#define GAIN_MIN_RAMP_MS "min_ramp_ms"
#define GAIN_MAX_RAMP_MS "max_ramp_ms"
+
+#define DYNAMIC_VALUE_TAG "dynamic" // special value for "channel_masks", "sampling_rates" and
+ // "formats" in outputs descriptors indicating that supported
+ // values should be queried after opening the output.
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
new file mode 100644
index 0000000..f66af6b
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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::AudioCollections"
+//#define LOG_NDEBUG 0
+
+#include "AudioCollections.h"
+#include "AudioPort.h"
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android {
+
+sp<AudioPort> AudioPortVector::findByTagName(const String8 &tagName) const
+{
+ sp<AudioPort> port = 0;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getTagName() == tagName) {
+ port = itemAt(i);
+ break;
+ }
+ }
+ return port;
+}
+
+status_t AudioRouteVector::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nAudio Route dump (%zu):\n", size());
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Route %zu:\n", i + 1);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd, 4);
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index 626fdae..9b6469c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -28,13 +28,11 @@
AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile)
: mIoHandle(0),
- mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0), mRefCount(0),
- mInputSource(AUDIO_SOURCE_DEFAULT), mProfile(profile), mIsSoundTrigger(false), mId(0)
+ mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL), mPatchHandle(0),
+ mProfile(profile), mId(0)
{
if (profile != NULL) {
- mSamplingRate = profile->pickSamplingRate();
- mFormat = profile->pickFormat();
- mChannelMask = profile->pickChannelMask();
+ profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (profile->mGains.size() > 0) {
profile->mGains[0]->getDefaultConfig(&mGain);
}
@@ -55,11 +53,23 @@
return mProfile->getModuleHandle();
}
+uint32_t AudioInputDescriptor::getOpenRefCount() const
+{
+ return mSessions.getOpenCount();
+}
+
audio_port_handle_t AudioInputDescriptor::getId() const
{
return mId;
}
+audio_source_t AudioInputDescriptor::inputSource() const
+{
+ // TODO: return highest priority input source
+ return mSessions.size() > 0 ? mSessions.valueAt(0)->inputSource() :
+ AUDIO_SOURCE_DEFAULT;
+}
+
void AudioInputDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
@@ -78,7 +88,7 @@
dstConfig->type = AUDIO_PORT_TYPE_MIX;
dstConfig->ext.mix.hw_module = getModuleHandle();
dstConfig->ext.mix.handle = mIoHandle;
- dstConfig->ext.mix.usecase.source = mInputSource;
+ dstConfig->ext.mix.usecase.source = inputSource();
}
void AudioInputDescriptor::toAudioPort(struct audio_port *port) const
@@ -113,6 +123,40 @@
mPreemptedSessions.clear();
}
+bool AudioInputDescriptor::isActive() const {
+ return mSessions.hasActiveSession();
+}
+
+bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
+{
+ return mSessions.isSourceActive(source);
+}
+
+bool AudioInputDescriptor::isSoundTrigger() const {
+ // sound trigger and non sound trigger sessions are not mixed
+ // on a given input
+ return mSessions.valueAt(0)->isSoundTrigger();
+}
+
+sp<AudioSession> AudioInputDescriptor::getAudioSession(
+ audio_session_t session) const {
+ return mSessions.valueFor(session);
+}
+
+AudioSessionCollection AudioInputDescriptor::getActiveAudioSessions() const
+{
+ return mSessions.getActiveSessions();
+}
+
+status_t AudioInputDescriptor::addAudioSession(audio_session_t session,
+ const sp<AudioSession>& audioSession) {
+ return mSessions.addSession(session, audioSession);
+}
+
+status_t AudioInputDescriptor::removeAudioSession(audio_session_t session) {
+ return mSessions.removeSession(session);
+}
+
status_t AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -129,13 +173,11 @@
result.append(buffer);
snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
result.append(buffer);
- snprintf(buffer, SIZE, " Ref Count %d\n", mRefCount);
- result.append(buffer);
- snprintf(buffer, SIZE, " Open Ref Count %d\n", mOpenRefCount);
- result.append(buffer);
write(fd, result.string(), result.size());
+ mSessions.dump(fd, 1);
+
return NO_ERROR;
}
@@ -143,10 +185,7 @@
{
for (size_t i = 0; i < size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
- if (inputDescriptor->mRefCount == 0) {
- continue;
- }
- if (inputDescriptor->mInputSource == (int)source) {
+ if (inputDescriptor->isSourceActive(source)) {
return true;
}
}
@@ -169,8 +208,8 @@
{
uint32_t count = 0;
for (size_t i = 0; i < size(); i++) {
- const sp<AudioInputDescriptor> desc = valueAt(i);
- if (desc->mRefCount > 0) {
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if (inputDescriptor->isActive()) {
count++;
}
}
@@ -180,9 +219,10 @@
audio_io_handle_t AudioInputCollection::getActiveInput(bool ignoreVirtualInputs)
{
for (size_t i = 0; i < size(); i++) {
- const sp<AudioInputDescriptor> input_descriptor = valueAt(i);
- if ((input_descriptor->mRefCount > 0)
- && (!ignoreVirtualInputs || !is_virtual_input_device(input_descriptor->mDevice))) {
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if ((inputDescriptor->isActive())
+ && (!ignoreVirtualInputs ||
+ !is_virtual_input_device(inputDescriptor->mDevice))) {
return keyAt(i);
}
}
@@ -192,7 +232,7 @@
audio_devices_t AudioInputCollection::getSupportedDevices(audio_io_handle_t handle) const
{
sp<AudioInputDescriptor> inputDesc = valueFor(handle);
- audio_devices_t devices = inputDesc->mProfile->mSupportedDevices.types();
+ audio_devices_t devices = inputDesc->mProfile->getSupportedDevicesType();
return devices;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index a278375..5d0f03f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -47,9 +47,7 @@
mStrategyMutedByDevice[i] = false;
}
if (port != NULL) {
- mSamplingRate = port->pickSamplingRate();
- mFormat = port->pickFormat();
- mChannelMask = port->pickChannelMask();
+ port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
if (port->mGains.size() > 0) {
port->mGains[0]->getDefaultConfig(&mGain);
}
@@ -220,15 +218,15 @@
}
// SwAudioOutputDescriptor implementation
-SwAudioOutputDescriptor::SwAudioOutputDescriptor(
- const sp<IOProfile>& profile, AudioPolicyClientInterface *clientInterface)
+SwAudioOutputDescriptor::SwAudioOutputDescriptor(const sp<IOProfile>& profile,
+ AudioPolicyClientInterface *clientInterface)
: AudioOutputDescriptor(profile, clientInterface),
mProfile(profile), mIoHandle(0), mLatency(0),
mFlags((audio_output_flags_t)0), mPolicyMix(NULL),
mOutput1(0), mOutput2(0), mDirectOpenCount(0), mGlobalRefCount(0)
{
if (profile != NULL) {
- mFlags = (audio_output_flags_t)profile->mFlags;
+ mFlags = (audio_output_flags_t)profile->getFlags();
}
}
@@ -283,7 +281,7 @@
if (isDuplicated()) {
return (audio_devices_t)(mOutput1->supportedDevices() | mOutput2->supportedDevices());
} else {
- return mProfile->mSupportedDevices.types() ;
+ return mProfile->getSupportedDevicesType();
}
}
@@ -388,8 +386,64 @@
return changed;
}
-// SwAudioOutputCollection implementation
+// HwAudioOutputDescriptor implementation
+HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ AudioPolicyClientInterface *clientInterface)
+ : AudioOutputDescriptor(source->mDevice, clientInterface),
+ mSource(source)
+{
+}
+status_t HwAudioOutputDescriptor::dump(int fd)
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ AudioOutputDescriptor::dump(fd);
+
+ snprintf(buffer, SIZE, "Source:\n");
+ result.append(buffer);
+ write(fd, result.string(), result.size());
+ mSource->dump(fd);
+
+ return NO_ERROR;
+}
+
+audio_devices_t HwAudioOutputDescriptor::supportedDevices()
+{
+ return mDevice;
+}
+
+void HwAudioOutputDescriptor::toAudioPortConfig(
+ struct audio_port_config *dstConfig,
+ const struct audio_port_config *srcConfig) const
+{
+ mSource->mDevice->toAudioPortConfig(dstConfig, srcConfig);
+}
+
+void HwAudioOutputDescriptor::toAudioPort(
+ struct audio_port *port) const
+{
+ mSource->mDevice->toAudioPort(port);
+}
+
+
+bool HwAudioOutputDescriptor::setVolume(float volume,
+ audio_stream_type_t stream,
+ audio_devices_t device,
+ uint32_t delayMs,
+ bool force)
+{
+ bool changed = AudioOutputDescriptor::setVolume(volume, stream, device, delayMs, force);
+
+ if (changed) {
+ // TODO: use gain controller on source device if any to adjust volume
+ }
+ return changed;
+}
+
+// SwAudioOutputCollection implementation
bool SwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
{
nsecs_t sysTime = systemTime();
@@ -473,7 +527,7 @@
audio_devices_t SwAudioOutputCollection::getSupportedDevices(audio_io_handle_t handle) const
{
sp<SwAudioOutputDescriptor> outputDesc = valueFor(handle);
- audio_devices_t devices = outputDesc->mProfile->mSupportedDevices.types();
+ audio_devices_t devices = outputDesc->mProfile->getSupportedDevicesType();
return devices;
}
@@ -494,4 +548,49 @@
return NO_ERROR;
}
+// HwAudioOutputCollection implementation
+bool HwAudioOutputCollection::isStreamActive(audio_stream_type_t stream, uint32_t inPastMs) const
+{
+ nsecs_t sysTime = systemTime();
+ for (size_t i = 0; i < this->size(); i++) {
+ const sp<HwAudioOutputDescriptor> outputDesc = this->valueAt(i);
+ if (outputDesc->isStreamActive(stream, inPastMs, sysTime)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool HwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
+{
+ for (size_t s = 0 ; s < AUDIO_STREAM_CNT ; s++) {
+ if (s == (size_t) streamToIgnore) {
+ continue;
+ }
+ for (size_t i = 0; i < size(); i++) {
+ const sp<HwAudioOutputDescriptor> outputDesc = valueAt(i);
+ if (outputDesc->mRefCount[s] != 0) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+status_t HwAudioOutputCollection::dump(int fd) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "\nOutputs dump:\n");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "- Output %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/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index a06d867..9c28e8f 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -19,7 +19,7 @@
#include "AudioPatch.h"
#include "AudioGain.h"
-#include "ConfigParsingUtils.h"
+#include "TypeConverter.h"
#include <cutils/log.h>
#include <utils/String8.h>
@@ -53,10 +53,11 @@
result.append(buffer);
for (size_t i = 0; i < mPatch.num_sources; i++) {
if (mPatch.sources[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ std::string device;
+ DeviceConverter::toString(mPatch.sources[i].ext.device.type, device);
snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sources[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- mPatch.sources[i].ext.device.type));
+ mPatch.sources[i].id,
+ device.c_str());
} else {
snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
mPatch.sources[i].id, mPatch.sources[i].ext.mix.handle);
@@ -67,10 +68,11 @@
result.append(buffer);
for (size_t i = 0; i < mPatch.num_sinks; i++) {
if (mPatch.sinks[i].type == AUDIO_PORT_TYPE_DEVICE) {
+ std::string device;
+ DeviceConverter::toString(mPatch.sinks[i].ext.device.type, device);
snprintf(buffer, SIZE, "%*s- Device ID %d %s\n", spaces + 2, "",
- mPatch.sinks[i].id, ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- mPatch.sinks[i].ext.device.type));
+ mPatch.sinks[i].id,
+ device.c_str());
} else {
snprintf(buffer, SIZE, "%*s- Mix ID %d I/O handle %d\n", spaces + 2, "",
mPatch.sinks[i].id, mPatch.sinks[i].ext.mix.handle);
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 4e24f19..cde0923 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -16,28 +16,21 @@
#define LOG_TAG "APM::AudioPort"
//#define LOG_NDEBUG 0
-#include <media/AudioResamplerPublic.h>
+#include "TypeConverter.h"
#include "AudioPort.h"
#include "HwModule.h"
#include "AudioGain.h"
-#include "ConfigParsingUtils.h"
-#include "audio_policy_conf.h"
#include <policy.h>
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
namespace android {
int32_t volatile AudioPort::mNextUniqueId = 1;
// --- AudioPort class implementation
-
-AudioPort::AudioPort(const String8& name, audio_port_type_t type,
- audio_port_role_t role) :
- mName(name), mType(type), mRole(role), mFlags(0)
-{
- mUseInChannelMask = ((type == AUDIO_PORT_TYPE_DEVICE) && (role == AUDIO_PORT_ROLE_SOURCE)) ||
- ((type == AUDIO_PORT_TYPE_MIX) && (role == AUDIO_PORT_ROLE_SINK));
-}
-
void AudioPort::attach(const sp<HwModule>& module)
{
mModule = module;
@@ -61,605 +54,178 @@
if (mModule == 0) {
return 0;
}
- return mModule->mHalVersion;
+ return mModule->getHalVersion();
}
const char *AudioPort::getModuleName() const
{
if (mModule == 0) {
- return "";
+ return "invalid module";
}
- return mModule->mName;
+ return mModule->getName();
}
void AudioPort::toAudioPort(struct audio_port *port) const
{
+ // TODO: update this function once audio_port structure reflects the new profile definition.
+ // For compatibility reason: flatening the AudioProfile into audio_port structure.
+ SortedVector<audio_format_t> flatenedFormats;
+ SampleRateVector flatenedRates;
+ ChannelsVector flatenedChannels;
+ for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+ if (mProfiles[profileIndex]->isValid()) {
+ audio_format_t formatToExport = mProfiles[profileIndex]->getFormat();
+ const SampleRateVector &ratesToExport = mProfiles[profileIndex]->getSampleRates();
+ const ChannelsVector &channelsToExport = mProfiles[profileIndex]->getChannels();
+
+ if (flatenedFormats.indexOf(formatToExport) < 0) {
+ flatenedFormats.add(formatToExport);
+ }
+ for (size_t rateIndex = 0; rateIndex < ratesToExport.size(); rateIndex++) {
+ uint32_t rate = ratesToExport[rateIndex];
+ if (flatenedRates.indexOf(rate) < 0) {
+ flatenedRates.add(rate);
+ }
+ }
+ for (size_t chanIndex = 0; chanIndex < channelsToExport.size(); chanIndex++) {
+ audio_channel_mask_t channels = channelsToExport[chanIndex];
+ if (flatenedChannels.indexOf(channels) < 0) {
+ flatenedChannels.add(channels);
+ }
+ }
+ if (flatenedRates.size() > AUDIO_PORT_MAX_SAMPLING_RATES ||
+ flatenedChannels.size() > AUDIO_PORT_MAX_CHANNEL_MASKS ||
+ flatenedFormats.size() > AUDIO_PORT_MAX_FORMATS) {
+ ALOGE("%s: bailing out: cannot export profiles to port config", __FUNCTION__);
+ return;
+ }
+ }
+ }
port->role = mRole;
port->type = mType;
strlcpy(port->name, mName, AUDIO_PORT_MAX_NAME_LEN);
- unsigned int i;
- for (i = 0; i < mSamplingRates.size() && i < AUDIO_PORT_MAX_SAMPLING_RATES; i++) {
- if (mSamplingRates[i] != 0) {
- port->sample_rates[i] = mSamplingRates[i];
- }
+ port->num_sample_rates = flatenedRates.size();
+ port->num_channel_masks = flatenedChannels.size();
+ port->num_formats = flatenedFormats.size();
+ for (size_t i = 0; i < flatenedRates.size(); i++) {
+ port->sample_rates[i] = flatenedRates[i];
}
- port->num_sample_rates = i;
- for (i = 0; i < mChannelMasks.size() && i < AUDIO_PORT_MAX_CHANNEL_MASKS; i++) {
- if (mChannelMasks[i] != 0) {
- port->channel_masks[i] = mChannelMasks[i];
- }
+ for (size_t i = 0; i < flatenedChannels.size(); i++) {
+ port->channel_masks[i] = flatenedChannels[i];
}
- port->num_channel_masks = i;
- for (i = 0; i < mFormats.size() && i < AUDIO_PORT_MAX_FORMATS; i++) {
- if (mFormats[i] != 0) {
- port->formats[i] = mFormats[i];
- }
+ for (size_t i = 0; i < flatenedFormats.size(); i++) {
+ port->formats[i] = flatenedFormats[i];
}
- port->num_formats = i;
ALOGV("AudioPort::toAudioPort() num gains %zu", mGains.size());
+ uint32_t i;
for (i = 0; i < mGains.size() && i < AUDIO_PORT_MAX_GAINS; i++) {
- port->gains[i] = mGains[i]->mGain;
+ port->gains[i] = mGains[i]->getGain();
}
port->num_gains = i;
}
-void AudioPort::importAudioPort(const sp<AudioPort> port) {
- for (size_t k = 0 ; k < port->mSamplingRates.size() ; k++) {
- const uint32_t rate = port->mSamplingRates.itemAt(k);
- if (rate != 0) { // skip "dynamic" rates
- bool hasRate = false;
- for (size_t l = 0 ; l < mSamplingRates.size() ; l++) {
- if (rate == mSamplingRates.itemAt(l)) {
- hasRate = true;
+void AudioPort::importAudioPort(const sp<AudioPort> port)
+{
+ size_t indexToImport;
+ for (indexToImport = 0; indexToImport < port->mProfiles.size(); indexToImport++) {
+ const sp<AudioProfile> &profileToImport = port->mProfiles[indexToImport];
+ if (profileToImport->isValid()) {
+ // Import only valid port, i.e. valid format, non empty rates and channels masks
+ bool hasSameProfile = false;
+ for (size_t profileIndex = 0; profileIndex < mProfiles.size(); profileIndex++) {
+ if (*mProfiles[profileIndex] == *profileToImport) {
+ // never import a profile twice
+ hasSameProfile = true;
break;
}
}
- if (!hasRate) { // never import a sampling rate twice
- mSamplingRates.add(rate);
+ if (hasSameProfile) { // never import a same profile twice
+ continue;
}
- }
- }
- for (size_t k = 0 ; k < port->mChannelMasks.size() ; k++) {
- const audio_channel_mask_t mask = port->mChannelMasks.itemAt(k);
- if (mask != 0) { // skip "dynamic" masks
- bool hasMask = false;
- for (size_t l = 0 ; l < mChannelMasks.size() ; l++) {
- if (mask == mChannelMasks.itemAt(l)) {
- hasMask = true;
- break;
- }
- }
- if (!hasMask) { // never import a channel mask twice
- mChannelMasks.add(mask);
- }
- }
- }
- for (size_t k = 0 ; k < port->mFormats.size() ; k++) {
- const audio_format_t format = port->mFormats.itemAt(k);
- if (format != 0) { // skip "dynamic" formats
- bool hasFormat = false;
- for (size_t l = 0 ; l < mFormats.size() ; l++) {
- if (format == mFormats.itemAt(l)) {
- hasFormat = true;
- break;
- }
- }
- if (!hasFormat) { // never import a format twice
- mFormats.add(format);
- }
+ addAudioProfile(profileToImport);
}
}
}
-void AudioPort::clearCapabilities() {
- mChannelMasks.clear();
- mFormats.clear();
- mSamplingRates.clear();
-}
-
-void AudioPort::loadSamplingRates(char *name)
+void AudioPort::pickSamplingRate(uint32_t &pickedRate,const SampleRateVector &samplingRates) const
{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mSamplingRates indicates the supported sampling
- // rates should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mSamplingRates.add(0);
- return;
- }
-
- while (str != NULL) {
- uint32_t rate = atoi(str);
- if (rate != 0) {
- ALOGV("loadSamplingRates() adding rate %d", rate);
- mSamplingRates.add(rate);
- }
- str = strtok(NULL, "|");
- }
-}
-
-void AudioPort::loadFormats(char *name)
-{
- char *str = strtok(name, "|");
-
- // by convention, "0' in the first entry in mFormats indicates the supported formats
- // should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mFormats.add(AUDIO_FORMAT_DEFAULT);
- return;
- }
-
- while (str != NULL) {
- audio_format_t format = (audio_format_t)ConfigParsingUtils::stringToEnum(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- str);
- if (format != AUDIO_FORMAT_DEFAULT) {
- mFormats.add(format);
- }
- str = strtok(NULL, "|");
- }
- // 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);
- // }
- mFormats.sort(compareFormats);
-}
-
-void AudioPort::loadInChannels(char *name)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadInChannels() %s", name);
-
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mChannelMasks.add(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- str);
- if (channelMask == 0) { // if not found, check the channel index table
- channelMask = (audio_channel_mask_t)
- ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable,
- ARRAY_SIZE(sIndexChannelsNameToEnumTable),
- str);
- }
- if (channelMask != 0) {
- ALOGV("loadInChannels() adding channelMask %#x", channelMask);
- mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
-}
-
-void AudioPort::loadOutChannels(char *name)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadOutChannels() %s", name);
-
- // by convention, "0' in the first entry in mChannelMasks indicates the supported channel
- // masks should be read from the output stream after it is opened for the first time
- if (str != NULL && strcmp(str, DYNAMIC_VALUE_TAG) == 0) {
- mChannelMasks.add(0);
- return;
- }
-
- while (str != NULL) {
- audio_channel_mask_t channelMask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
- ARRAY_SIZE(sOutChannelsNameToEnumTable),
- str);
- if (channelMask == 0) { // if not found, check the channel index table
- channelMask = (audio_channel_mask_t)
- ConfigParsingUtils::stringToEnum(sIndexChannelsNameToEnumTable,
- ARRAY_SIZE(sIndexChannelsNameToEnumTable),
- str);
- }
- if (channelMask != 0) {
- mChannelMasks.add(channelMask);
- }
- str = strtok(NULL, "|");
- }
- return;
-}
-
-audio_gain_mode_t AudioPort::loadGainMode(char *name)
-{
- const char *str = strtok(name, "|");
-
- ALOGV("loadGainMode() %s", name);
- audio_gain_mode_t mode = 0;
- while (str != NULL) {
- mode |= (audio_gain_mode_t)ConfigParsingUtils::stringToEnum(sGainModeNameToEnumTable,
- ARRAY_SIZE(sGainModeNameToEnumTable),
- str);
- str = strtok(NULL, "|");
- }
- return mode;
-}
-
-void AudioPort::loadGain(cnode *root, int index)
-{
- cnode *node = root->first_child;
-
- sp<AudioGain> gain = new AudioGain(index, mUseInChannelMask);
-
- while (node) {
- if (strcmp(node->name, GAIN_MODE) == 0) {
- gain->mGain.mode = loadGainMode((char *)node->value);
- } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
- if (mUseInChannelMask) {
- gain->mGain.channel_mask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sInChannelsNameToEnumTable,
- ARRAY_SIZE(sInChannelsNameToEnumTable),
- (char *)node->value);
- } else {
- gain->mGain.channel_mask =
- (audio_channel_mask_t)ConfigParsingUtils::stringToEnum(sOutChannelsNameToEnumTable,
- ARRAY_SIZE(sOutChannelsNameToEnumTable),
- (char *)node->value);
- }
- } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
- gain->mGain.min_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
- gain->mGain.max_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
- gain->mGain.default_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
- gain->mGain.step_value = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
- gain->mGain.min_ramp_ms = atoi((char *)node->value);
- } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
- gain->mGain.max_ramp_ms = atoi((char *)node->value);
- }
- node = node->next;
- }
-
- ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
- gain->mGain.mode, gain->mGain.channel_mask, gain->mGain.min_value, gain->mGain.max_value);
-
- if (gain->mGain.mode == 0) {
- return;
- }
- mGains.add(gain);
-}
-
-void AudioPort::loadGains(cnode *root)
-{
- cnode *node = root->first_child;
- int index = 0;
- while (node) {
- ALOGV("loadGains() loading gain %s", node->name);
- loadGain(node, index++);
- node = node->next;
- }
-}
-
-status_t AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
-{
- if (mSamplingRates.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if (mSamplingRates[i] == samplingRate) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
- uint32_t *updatedSamplingRate) const
-{
- if (mSamplingRates.isEmpty()) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = samplingRate;
- }
- return NO_ERROR;
- }
-
- // Search for the closest supported sampling rate that is above (preferred)
- // or below (acceptable) the desired sampling rate, within a permitted ratio.
- // The sampling rates do not need to be sorted in ascending order.
- ssize_t maxBelow = -1;
- ssize_t minAbove = -1;
- uint32_t candidate;
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- candidate = mSamplingRates[i];
- if (candidate == samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- // candidate < desired
- if (candidate < samplingRate) {
- if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
- maxBelow = i;
- }
- // candidate > desired
- } else {
- if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
- minAbove = i;
- }
- }
- }
-
- // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
- if (minAbove >= 0) {
- candidate = mSamplingRates[minAbove];
- if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- }
- // But if we have to up-sample from a lower sampling rate, that's OK.
- if (maxBelow >= 0) {
- candidate = mSamplingRates[maxBelow];
- if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
- if (updatedSamplingRate != NULL) {
- *updatedSamplingRate = candidate;
- }
- return NO_ERROR;
- }
- }
- // leave updatedSamplingRate unmodified
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
-{
- if (mChannelMasks.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- if (mChannelMasks[i] == channelMask) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
- audio_channel_mask_t *updatedChannelMask) const
-{
- if (mChannelMasks.isEmpty()) {
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = channelMask;
- }
- return NO_ERROR;
- }
-
- const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
- const bool isIndex = audio_channel_mask_get_representation(channelMask)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX;
- int bestMatch = 0;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- audio_channel_mask_t supported = mChannelMasks[i];
- if (supported == channelMask) {
- // Exact matches always taken.
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = channelMask;
- }
- return NO_ERROR;
- }
-
- // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
- if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
- // Approximate (best) match:
- // The match score measures how well the supported channel mask matches the
- // desired mask, where increasing-is-better.
- //
- // TODO: Some tweaks may be needed.
- // Should be a static function of the data processing library.
- //
- // In priority:
- // match score = 1000 if legacy channel conversion equivalent (always prefer this)
- // OR
- // match score += 100 if the channel mask representations match
- // match score += number of channels matched.
- //
- // If there are no matched channels, the mask may still be accepted
- // but the playback or record will be silent.
- const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
- == AUDIO_CHANNEL_REPRESENTATION_INDEX);
- int match;
- if (isIndex && isSupportedIndex) {
- // index equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- } else if (isIndex && !isSupportedIndex) {
- const uint32_t equivalentBits =
- (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
- match = __builtin_popcount(
- audio_channel_mask_get_bits(channelMask) & equivalentBits);
- } else if (!isIndex && isSupportedIndex) {
- const uint32_t equivalentBits =
- (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
- match = __builtin_popcount(
- equivalentBits & audio_channel_mask_get_bits(supported));
- } else {
- // positional equivalence
- match = 100 + __builtin_popcount(
- audio_channel_mask_get_bits(channelMask)
- & audio_channel_mask_get_bits(supported));
- switch (supported) {
- case AUDIO_CHANNEL_IN_FRONT_BACK:
- case AUDIO_CHANNEL_IN_STEREO:
- if (channelMask == AUDIO_CHANNEL_IN_MONO) {
- match = 1000;
- }
- break;
- case AUDIO_CHANNEL_IN_MONO:
- if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
- || channelMask == AUDIO_CHANNEL_IN_STEREO) {
- match = 1000;
- }
- break;
- default:
- break;
- }
- }
- if (match > bestMatch) {
- bestMatch = match;
- if (updatedChannelMask != NULL) {
- *updatedChannelMask = supported;
- } else {
- return NO_ERROR; // any match will do in this case.
- }
- }
- }
- }
- return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
-}
-
-status_t AudioPort::checkExactFormat(audio_format_t format) const
-{
- if (mFormats.isEmpty()) {
- return NO_ERROR;
- }
-
- for (size_t i = 0; i < mFormats.size(); i ++) {
- if (mFormats[i] == format) {
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-status_t AudioPort::checkCompatibleFormat(audio_format_t format, audio_format_t *updatedFormat)
- const
-{
- if (mFormats.isEmpty()) {
- if (updatedFormat != NULL) {
- *updatedFormat = format;
- }
- return NO_ERROR;
- }
-
- const bool checkInexact = // when port is input and format is linear pcm
- mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK
- && audio_is_linear_pcm(format);
-
- // iterate from best format to worst format (reverse order)
- for (ssize_t i = mFormats.size() - 1; i >= 0 ; --i) {
- if (mFormats[i] == format ||
- (checkInexact
- && mFormats[i] != AUDIO_FORMAT_DEFAULT
- && audio_is_linear_pcm(mFormats[i]))) {
- // for inexact checks we take the first linear pcm format due to sorting.
- if (updatedFormat != NULL) {
- *updatedFormat = mFormats[i];
- }
- return NO_ERROR;
- }
- }
- return BAD_VALUE;
-}
-
-uint32_t AudioPort::pickSamplingRate() const
-{
- // special case for uninitialized dynamic profile
- if (mSamplingRates.size() == 1 && mSamplingRates[0] == 0) {
- return 0;
- }
-
+ pickedRate = 0;
// For direct outputs, pick minimum sampling rate: this helps ensuring that the
// channel count / sampling rate combination chosen will be supported by the connected
// sink
- if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+ if (isDirectOutput()) {
uint32_t samplingRate = UINT_MAX;
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] < samplingRate) && (mSamplingRates[i] > 0)) {
- samplingRate = mSamplingRates[i];
+ for (size_t i = 0; i < samplingRates.size(); i ++) {
+ if ((samplingRates[i] < samplingRate) && (samplingRates[i] > 0)) {
+ samplingRate = samplingRates[i];
}
}
- return (samplingRate == UINT_MAX) ? 0 : samplingRate;
- }
+ pickedRate = (samplingRate == UINT_MAX) ? 0 : samplingRate;
+ } else {
+ uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
- uint32_t samplingRate = 0;
- uint32_t maxRate = MAX_MIXER_SAMPLING_RATE;
-
- // For mixed output and inputs, use max mixer sampling rates. Do not
- // limit sampling rate otherwise
- // For inputs, also see checkCompatibleSamplingRate().
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxRate = UINT_MAX;
- }
- // TODO: should mSamplingRates[] be ordered in terms of our preference
- // and we return the first (and hence most preferred) match? This is of concern if
- // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
- for (size_t i = 0; i < mSamplingRates.size(); i ++) {
- if ((mSamplingRates[i] > samplingRate) && (mSamplingRates[i] <= maxRate)) {
- samplingRate = mSamplingRates[i];
+ // For mixed output and inputs, use max mixer sampling rates. Do not
+ // limit sampling rate otherwise
+ // For inputs, also see checkCompatibleSamplingRate().
+ if (mType != AUDIO_PORT_TYPE_MIX) {
+ maxRate = UINT_MAX;
+ }
+ // TODO: should mSamplingRates[] be ordered in terms of our preference
+ // and we return the first (and hence most preferred) match? This is of concern if
+ // we want to choose 96kHz over 192kHz for USB driver stability or resource constraints.
+ for (size_t i = 0; i < samplingRates.size(); i ++) {
+ if ((samplingRates[i] > pickedRate) && (samplingRates[i] <= maxRate)) {
+ pickedRate = samplingRates[i];
+ }
}
}
- return samplingRate;
}
-audio_channel_mask_t AudioPort::pickChannelMask() const
+void AudioPort::pickChannelMask(audio_channel_mask_t &pickedChannelMask,
+ const ChannelsVector &channelMasks) const
{
- // special case for uninitialized dynamic profile
- if (mChannelMasks.size() == 1 && mChannelMasks[0] == 0) {
- return AUDIO_CHANNEL_NONE;
- }
- audio_channel_mask_t channelMask = AUDIO_CHANNEL_NONE;
-
+ pickedChannelMask = AUDIO_CHANNEL_NONE;
// For direct outputs, pick minimum channel count: this helps ensuring that the
// channel count / sampling rate combination chosen will be supported by the connected
// sink
- if ((mType == AUDIO_PORT_TYPE_MIX) && (mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))) {
+ if (isDirectOutput()) {
uint32_t channelCount = UINT_MAX;
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ for (size_t i = 0; i < channelMasks.size(); i ++) {
uint32_t cnlCount;
- if (mUseInChannelMask) {
- cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
+ if (useInputChannelMask()) {
+ cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
} else {
- cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+ cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
}
if ((cnlCount < channelCount) && (cnlCount > 0)) {
- channelMask = mChannelMasks[i];
+ pickedChannelMask = channelMasks[i];
channelCount = cnlCount;
}
}
- return channelMask;
- }
+ } else {
+ uint32_t channelCount = 0;
+ uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
- uint32_t channelCount = 0;
- uint32_t maxCount = MAX_MIXER_CHANNEL_COUNT;
-
- // For mixed output and inputs, use max mixer channel count. Do not
- // limit channel count otherwise
- if (mType != AUDIO_PORT_TYPE_MIX) {
- maxCount = UINT_MAX;
- }
- for (size_t i = 0; i < mChannelMasks.size(); i ++) {
- uint32_t cnlCount;
- if (mUseInChannelMask) {
- cnlCount = audio_channel_count_from_in_mask(mChannelMasks[i]);
- } else {
- cnlCount = audio_channel_count_from_out_mask(mChannelMasks[i]);
+ // For mixed output and inputs, use max mixer channel count. Do not
+ // limit channel count otherwise
+ if (mType != AUDIO_PORT_TYPE_MIX) {
+ maxCount = UINT_MAX;
}
- if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
- channelMask = mChannelMasks[i];
- channelCount = cnlCount;
+ for (size_t i = 0; i < channelMasks.size(); i ++) {
+ uint32_t cnlCount;
+ if (useInputChannelMask()) {
+ cnlCount = audio_channel_count_from_in_mask(channelMasks[i]);
+ } else {
+ cnlCount = audio_channel_count_from_out_mask(channelMasks[i]);
+ }
+ if ((cnlCount > channelCount) && (cnlCount <= maxCount)) {
+ pickedChannelMask = channelMasks[i];
+ channelCount = cnlCount;
+ }
}
}
- return channelMask;
}
/* format in order of increasing preference */
@@ -672,8 +238,7 @@
AUDIO_FORMAT_PCM_FLOAT,
};
-int AudioPort::compareFormats(audio_format_t format1,
- audio_format_t format2)
+int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
{
// NOTE: AUDIO_FORMAT_INVALID is also considered not PCM and will be compared equal to any
// compressed format and better than any PCM format. This is by design of pickFormat()
@@ -703,36 +268,49 @@
return index1 - index2;
}
-audio_format_t AudioPort::pickFormat() const
+void AudioPort::pickAudioProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format) const
{
- // special case for uninitialized dynamic profile
- if (mFormats.size() == 1 && mFormats[0] == 0) {
- return AUDIO_FORMAT_DEFAULT;
- }
+ format = AUDIO_FORMAT_DEFAULT;
+ samplingRate = 0;
+ channelMask = AUDIO_CHANNEL_NONE;
- audio_format_t format = AUDIO_FORMAT_DEFAULT;
- audio_format_t bestFormat =
- AudioPort::sPcmFormatCompareTable[
- ARRAY_SIZE(AudioPort::sPcmFormatCompareTable) - 1];
- // For mixed output and inputs, use best mixer output format. Do not
- // limit format otherwise
- if ((mType != AUDIO_PORT_TYPE_MIX) ||
- ((mRole == AUDIO_PORT_ROLE_SOURCE) &&
- (((mFlags & (AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) != 0)))) {
+ // special case for uninitialized dynamic profile
+ if (!mProfiles.hasValidProfile()) {
+ return;
+ }
+ audio_format_t bestFormat = sPcmFormatCompareTable[ARRAY_SIZE(sPcmFormatCompareTable) - 1];
+ // For mixed output and inputs, use best mixer output format.
+ // Do not limit format otherwise
+ if ((mType != AUDIO_PORT_TYPE_MIX) || isDirectOutput()) {
bestFormat = AUDIO_FORMAT_INVALID;
}
- for (size_t i = 0; i < mFormats.size(); i ++) {
- if ((compareFormats(mFormats[i], format) > 0) &&
- (compareFormats(mFormats[i], bestFormat) <= 0)) {
- format = mFormats[i];
+ for (size_t i = 0; i < mProfiles.size(); i ++) {
+ if (!mProfiles[i]->isValid()) {
+ continue;
+ }
+ audio_format_t formatToCompare = mProfiles[i]->getFormat();
+ if ((compareFormats(formatToCompare, format) > 0) &&
+ (compareFormats(formatToCompare, bestFormat) <= 0)) {
+ uint32_t pickedSamplingRate = 0;
+ audio_channel_mask_t pickedChannelMask = AUDIO_CHANNEL_NONE;
+ pickChannelMask(pickedChannelMask, mProfiles[i]->getChannels());
+ pickSamplingRate(pickedSamplingRate, mProfiles[i]->getSampleRates());
+
+ if (formatToCompare != AUDIO_FORMAT_DEFAULT && pickedChannelMask != AUDIO_CHANNEL_NONE
+ && pickedSamplingRate != 0) {
+ format = formatToCompare;
+ channelMask = pickedChannelMask;
+ samplingRate = pickedSamplingRate;
+ // TODO: shall we return on the first one or still trying to pick a better Profile?
+ }
}
}
- return format;
}
-status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig,
- int index) const
+status_t AudioPort::checkGain(const struct audio_gain_config *gainConfig, int index) const
{
if (index < 0 || (size_t)index >= mGains.size()) {
return BAD_VALUE;
@@ -740,7 +318,7 @@
return mGains[index]->checkConfig(gainConfig);
}
-void AudioPort::dump(int fd, int spaces) const
+void AudioPort::dump(int fd, int spaces, bool verbose) const
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -749,68 +327,17 @@
if (mName.length() != 0) {
snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
result.append(buffer);
+ write(fd, result.string(), result.size());
}
+ if (verbose) {
+ mProfiles.dump(fd, spaces);
- if (mSamplingRates.size() != 0) {
- snprintf(buffer, SIZE, "%*s- sampling rates: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- if (i == 0 && mSamplingRates[i] == 0) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ if (mGains.size() != 0) {
+ snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
+ write(fd, buffer, strlen(buffer) + 1);
+ for (size_t i = 0; i < mGains.size(); i++) {
+ mGains[i]->dump(fd, spaces + 2, i);
}
- result.append(buffer);
- result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
-
- if (mChannelMasks.size() != 0) {
- snprintf(buffer, SIZE, "%*s- channel masks: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- ALOGV("AudioPort::dump mChannelMasks %zu %08x", i, mChannelMasks[i]);
-
- if (i == 0 && mChannelMasks[i] == 0) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
- }
- result.append(buffer);
- result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
-
- if (mFormats.size() != 0) {
- snprintf(buffer, SIZE, "%*s- formats: ", spaces, "");
- result.append(buffer);
- for (size_t i = 0; i < mFormats.size(); i++) {
- const char *formatStr = ConfigParsingUtils::enumToString(sFormatNameToEnumTable,
- ARRAY_SIZE(sFormatNameToEnumTable),
- mFormats[i]);
- const bool isEmptyStr = formatStr[0] == 0;
- if (i == 0 && isEmptyStr) {
- snprintf(buffer, SIZE, "Dynamic");
- } else {
- if (isEmptyStr) {
- snprintf(buffer, SIZE, "%#x", mFormats[i]);
- } else {
- snprintf(buffer, SIZE, "%s", formatStr);
- }
- }
- result.append(buffer);
- result.append(i == (mFormats.size() - 1) ? "" : ", ");
- }
- result.append("\n");
- }
- write(fd, result.string(), result.size());
- if (mGains.size() != 0) {
- snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
- write(fd, buffer, strlen(buffer) + 1);
- for (size_t i = 0; i < mGains.size(); i++) {
- mGains[i]->dump(fd, spaces + 2, i);
}
}
}
@@ -830,9 +357,8 @@
mGain.index = -1;
}
-status_t AudioPortConfig::applyAudioPortConfig(
- const struct audio_port_config *config,
- struct audio_port_config *backupConfig)
+status_t AudioPortConfig::applyAudioPortConfig(const struct audio_port_config *config,
+ struct audio_port_config *backupConfig)
{
struct audio_port_config localBackupConfig;
status_t status = NO_ERROR;
@@ -845,25 +371,19 @@
status = NO_INIT;
goto exit;
}
+ status = audioport->checkExactAudioProfile(config->sample_rate,
+ config->channel_mask,
+ config->format);
+ if (status != NO_ERROR) {
+ goto exit;
+ }
if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
- status = audioport->checkExactSamplingRate(config->sample_rate);
- if (status != NO_ERROR) {
- goto exit;
- }
mSamplingRate = config->sample_rate;
}
if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
- status = audioport->checkExactChannelMask(config->channel_mask);
- if (status != NO_ERROR) {
- goto exit;
- }
mChannelMask = config->channel_mask;
}
if (config->config_mask & AUDIO_PORT_CONFIG_FORMAT) {
- status = audioport->checkExactFormat(config->format);
- if (status != NO_ERROR) {
- goto exit;
- }
mFormat = config->format;
}
if (config->config_mask & AUDIO_PORT_CONFIG_GAIN) {
@@ -911,9 +431,11 @@
} else {
dstConfig->format = AUDIO_FORMAT_INVALID;
}
- if (dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) {
+ sp<AudioPort> audioport = getAudioPort();
+ if ((dstConfig->config_mask & AUDIO_PORT_CONFIG_GAIN) && audioport != NULL) {
dstConfig->gain = mGain;
- if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)) {
+ if ((srcConfig != NULL) && (srcConfig->config_mask & AUDIO_PORT_CONFIG_GAIN)
+ && audioport->checkGain(&srcConfig->gain, srcConfig->gain.index) == OK) {
dstConfig->gain = srcConfig->gain;
}
} else {
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
new file mode 100644
index 0000000..c599665
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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::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>
+
+namespace android {
+
+status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
+ audio_format_t format) const
+{
+ if (format == mFormat &&
+ (mChannelMasks.isEmpty() || supportsChannels(channelMask)) &&
+ (mSamplingRates.isEmpty() || supportsRate(samplingRate))) {
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+template <typename T>
+bool operator == (const SortedVector<T> &left, const SortedVector<T> &right)
+{
+ if (left.size() != right.size()) {
+ return false;
+ }
+ for(size_t index = 0; index < right.size(); index++) {
+ if (left[index] != right[index]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+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
+{
+ if (mSamplingRates.isEmpty()) {
+ updatedSamplingRate = samplingRate;
+ return NO_ERROR;
+ }
+ // Search for the closest supported sampling rate that is above (preferred)
+ // or below (acceptable) the desired sampling rate, within a permitted ratio.
+ // The sampling rates are sorted in ascending order.
+ size_t orderOfDesiredRate = mSamplingRates.orderOf(samplingRate);
+
+ // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
+ if (orderOfDesiredRate < mSamplingRates.size()) {
+ uint32_t candidate = mSamplingRates[orderOfDesiredRate];
+ if (candidate / AUDIO_RESAMPLER_DOWN_RATIO_MAX <= samplingRate) {
+ updatedSamplingRate = candidate;
+ return NO_ERROR;
+ }
+ }
+ // But if we have to up-sample from a lower sampling rate, that's OK.
+ if (orderOfDesiredRate != 0) {
+ uint32_t candidate = mSamplingRates[orderOfDesiredRate - 1];
+ if (candidate * AUDIO_RESAMPLER_UP_RATIO_MAX >= samplingRate) {
+ updatedSamplingRate = candidate;
+ return NO_ERROR;
+ }
+ }
+ // leave updatedSamplingRate unmodified
+ return BAD_VALUE;
+}
+
+status_t AudioProfile::checkCompatibleChannelMask(audio_channel_mask_t channelMask,
+ audio_channel_mask_t &updatedChannelMask,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const
+{
+ if (mChannelMasks.isEmpty()) {
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+ const bool isRecordThread = portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK;
+ const bool isIndex = audio_channel_mask_get_representation(channelMask)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX;
+ int bestMatch = 0;
+ for (size_t i = 0; i < mChannelMasks.size(); i ++) {
+ audio_channel_mask_t supported = mChannelMasks[i];
+ if (supported == channelMask) {
+ // Exact matches always taken.
+ updatedChannelMask = channelMask;
+ return NO_ERROR;
+ }
+
+ // AUDIO_CHANNEL_NONE (value: 0) is used for dynamic channel support
+ if (isRecordThread && supported != AUDIO_CHANNEL_NONE) {
+ // Approximate (best) match:
+ // The match score measures how well the supported channel mask matches the
+ // desired mask, where increasing-is-better.
+ //
+ // TODO: Some tweaks may be needed.
+ // Should be a static function of the data processing library.
+ //
+ // In priority:
+ // match score = 1000 if legacy channel conversion equivalent (always prefer this)
+ // OR
+ // match score += 100 if the channel mask representations match
+ // match score += number of channels matched.
+ //
+ // If there are no matched channels, the mask may still be accepted
+ // but the playback or record will be silent.
+ const bool isSupportedIndex = (audio_channel_mask_get_representation(supported)
+ == AUDIO_CHANNEL_REPRESENTATION_INDEX);
+ int match;
+ if (isIndex && isSupportedIndex) {
+ // index equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ } else if (isIndex && !isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(supported)) - 1 ;
+ match = __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask) & equivalentBits);
+ } else if (!isIndex && isSupportedIndex) {
+ const uint32_t equivalentBits =
+ (1 << audio_channel_count_from_in_mask(channelMask)) - 1;
+ match = __builtin_popcount(
+ equivalentBits & audio_channel_mask_get_bits(supported));
+ } else {
+ // positional equivalence
+ match = 100 + __builtin_popcount(
+ audio_channel_mask_get_bits(channelMask)
+ & audio_channel_mask_get_bits(supported));
+ switch (supported) {
+ case AUDIO_CHANNEL_IN_FRONT_BACK:
+ case AUDIO_CHANNEL_IN_STEREO:
+ if (channelMask == AUDIO_CHANNEL_IN_MONO) {
+ match = 1000;
+ }
+ break;
+ case AUDIO_CHANNEL_IN_MONO:
+ if (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
+ || channelMask == AUDIO_CHANNEL_IN_STEREO) {
+ match = 1000;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ if (match > bestMatch) {
+ bestMatch = match;
+ updatedChannelMask = supported;
+ }
+ }
+ }
+ return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
+}
+
+void AudioProfile::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+ mIsDynamicChannels ? "[dynamic channels]" : "",
+ mIsDynamicRate ? "[dynamic rates]" : "");
+ result.append(buffer);
+ if (mName.length() != 0) {
+ snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
+ result.append(buffer);
+ }
+ std::string formatLiteral;
+ if (FormatConverter::toString(mFormat, formatLiteral)) {
+ snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
+ result.append(buffer);
+ }
+ if (!mSamplingRates.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mSamplingRates.size(); i++) {
+ snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
+ result.append(buffer);
+ result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+ }
+ result.append("\n");
+ }
+
+ if (!mChannelMasks.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mChannelMasks.size(); i++) {
+ snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
+ result.append(buffer);
+ result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+ }
+ result.append("\n");
+ }
+ write(fd, result.string(), result.size());
+}
+
+status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
+ audio_channel_mask_t channelMask,
+ audio_format_t format) const
+{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
+
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioProfile> profile = itemAt(i);
+ if (profile->checkExact(samplingRate, channelMask, format) == NO_ERROR) {
+ return NO_ERROR;
+ }
+ }
+ return BAD_VALUE;
+}
+
+status_t AudioProfileVector::checkCompatibleProfile(uint32_t &samplingRate,
+ audio_channel_mask_t &channelMask,
+ audio_format_t &format,
+ audio_port_type_t portType,
+ audio_port_role_t portRole) const
+{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
+
+ const bool checkInexact = // when port is input and format is linear pcm
+ portType == AUDIO_PORT_TYPE_MIX && portRole == AUDIO_PORT_ROLE_SINK
+ && audio_is_linear_pcm(format);
+
+ // iterate from best format to worst format (reverse order)
+ for (ssize_t i = size() - 1; i >= 0 ; --i) {
+ const sp<AudioProfile> profile = itemAt(i);
+ audio_format_t formatToCompare = profile->getFormat();
+ if (formatToCompare == format ||
+ (checkInexact
+ && formatToCompare != AUDIO_FORMAT_DEFAULT
+ && audio_is_linear_pcm(formatToCompare))) {
+ // Compatible profile has been found, checks if this profile has compatible
+ // rate and channels as well
+ audio_channel_mask_t updatedChannels;
+ uint32_t updatedRate;
+ if (profile->checkCompatibleChannelMask(channelMask, updatedChannels,
+ portType, portRole) == NO_ERROR &&
+ profile->checkCompatibleSamplingRate(samplingRate, updatedRate) == NO_ERROR) {
+ // for inexact checks we take the first linear pcm format due to sorting.
+ format = formatToCompare;
+ channelMask = updatedChannels;
+ samplingRate = updatedRate;
+ return NO_ERROR;
+ }
+ }
+ }
+ return BAD_VALUE;
+}
+
+int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
+ const sp<AudioProfile> *profile2)
+{
+ return AudioPort::compareFormats((*profile1)->getFormat(), (*profile2)->getFormat());
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
new file mode 100644
index 0000000..79ad1f7
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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::AudioRoute"
+//#define LOG_NDEBUG 0
+
+#include "AudioRoute.h"
+#include "HwModule.h"
+#include "AudioGain.h"
+
+namespace android
+{
+
+void AudioRoute::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+ result.append(buffer);
+
+ snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
+ result.append(buffer);
+
+ if (mSources.size() != 0) {
+ snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
+ result.append(buffer);
+ for (size_t i = 0; i < mSources.size(); i++) {
+ snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
+ result.append(buffer);
+ }
+ }
+ result.append("\n");
+
+ write(fd, result.string(), result.size());
+}
+
+}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
new file mode 100644
index 0000000..597c029
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSession.cpp
@@ -0,0 +1,223 @@
+/*
+ * 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::AudioSession"
+//#define LOG_NDEBUG 0
+
+#include <AudioPolicyInterface.h>
+#include "AudioSession.h"
+#include "AudioGain.h"
+#include "TypeConverter.h"
+#include <cutils/log.h>
+#include <utils/String8.h>
+
+namespace android {
+
+AudioSession::AudioSession(audio_session_t session,
+ audio_source_t inputSource,
+ audio_format_t format,
+ uint32_t sampleRate,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ uid_t uid,
+ bool isSoundTrigger,
+ AudioMix* policyMix,
+ AudioPolicyClientInterface *clientInterface) :
+ mSession(session), mInputSource(inputSource),
+ mFormat(format), mSampleRate(sampleRate), mChannelMask(channelMask),
+ mFlags(flags), mUid(uid), mIsSoundTrigger(isSoundTrigger),
+ mOpenCount(1), mActiveCount(0), mPolicyMix(policyMix), mClientInterface(clientInterface)
+{
+}
+
+uint32_t AudioSession::changeOpenCount(int delta)
+{
+ if ((delta + (int)mOpenCount) < 0) {
+ ALOGW("%s invalid delta %d, open count %d",
+ __FUNCTION__, delta, mOpenCount);
+ mOpenCount = (uint32_t)(-delta);
+ }
+ mOpenCount += delta;
+ ALOGV("%s open count %d", __FUNCTION__, mOpenCount);
+ return mOpenCount;
+}
+
+uint32_t AudioSession::changeActiveCount(int delta)
+{
+ const uint32_t oldActiveCount = mActiveCount;
+ if ((delta + (int)mActiveCount) < 0) {
+ ALOGW("%s invalid delta %d, active count %d",
+ __FUNCTION__, delta, mActiveCount);
+ mActiveCount = (uint32_t)(-delta);
+ }
+ mActiveCount += delta;
+ ALOGV("%s active count %d", __FUNCTION__, mActiveCount);
+
+ if ((oldActiveCount == 0) && (mActiveCount > 0)) {
+ // if input maps to a dynamic policy with an activity listener, notify of state change
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ MIX_STATE_MIXING);
+ }
+ mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_START,
+ mSession, mInputSource);
+ } else if ((oldActiveCount > 0) && (mActiveCount == 0)) {
+ // if input maps to a dynamic policy with an activity listener, notify of state change
+ if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
+ {
+ mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId,
+ MIX_STATE_IDLE);
+ }
+ mClientInterface->onRecordingConfigurationUpdate(RECORD_CONFIG_EVENT_STOP,
+ mSession, mInputSource);
+ }
+
+ return mActiveCount;
+}
+
+bool AudioSession::matches(const sp<AudioSession> &other) const
+{
+ if (other->session() == mSession &&
+ other->inputSource() == mInputSource &&
+ other->format() == mFormat &&
+ other->sampleRate() == mSampleRate &&
+ other->channelMask() == mChannelMask &&
+ other->flags() == mFlags &&
+ other->uid() == mUid) {
+ return true;
+ }
+ return false;
+}
+
+
+status_t AudioSession::dump(int fd, int spaces, int index) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ String8 result;
+
+ snprintf(buffer, SIZE, "%*sAudio session %d:\n", spaces, "", index+1);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- session: %2d\n", spaces, "", mSession);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- owner uid: %2d\n", spaces, "", mUid);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- input source: %d\n", spaces, "", mInputSource);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- format: %08x\n", spaces, "", mFormat);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- sample: %d\n", spaces, "", mSampleRate);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- channel mask: %08x\n",
+ spaces, "", mChannelMask);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- is soundtrigger: %s\n",
+ spaces, "", mIsSoundTrigger ? "true" : "false");
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- open count: %d\n", spaces, "", mOpenCount);
+ result.append(buffer);
+ snprintf(buffer, SIZE, "%*s- active count: %d\n", spaces, "", mActiveCount);
+ result.append(buffer);
+
+ write(fd, result.string(), result.size());
+ return NO_ERROR;
+}
+
+status_t AudioSessionCollection::addSession(audio_session_t session,
+ const sp<AudioSession>& audioSession)
+{
+ ssize_t index = indexOfKey(session);
+
+ if (index >= 0) {
+ ALOGW("addSession() session %d already in", session);
+ return ALREADY_EXISTS;
+ }
+ add(session, audioSession);
+ ALOGV("addSession() session %d client %d source %d",
+ session, audioSession->uid(), audioSession->inputSource());
+ return NO_ERROR;
+}
+
+status_t AudioSessionCollection::removeSession(audio_session_t session)
+{
+ ssize_t index = indexOfKey(session);
+
+ if (index < 0) {
+ ALOGW("removeSession() session %d not in", session);
+ return ALREADY_EXISTS;
+ }
+ ALOGV("removeSession() session %d", session);
+ removeItemsAt(index);
+ return NO_ERROR;
+}
+
+uint32_t AudioSessionCollection::getOpenCount() const
+{
+ uint32_t openCount = 0;
+ for (size_t i = 0; i < size(); i++) {
+ openCount += valueAt(i)->openCount();
+ }
+ return openCount;
+}
+
+AudioSessionCollection AudioSessionCollection::getActiveSessions() const
+{
+ AudioSessionCollection activeSessions;
+ for (size_t i = 0; i < size(); i++) {
+ if (valueAt(i)->activeCount() != 0) {
+ activeSessions.add(valueAt(i)->session(), valueAt(i));
+ }
+ }
+ return activeSessions;
+}
+
+bool AudioSessionCollection::hasActiveSession() const
+{
+ return getActiveSessions().size() != 0;
+}
+
+bool AudioSessionCollection::isSourceActive(audio_source_t source) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ const sp<AudioSession> audioSession = valueAt(i);
+ // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
+ // corresponds to an active capture triggered by a hardware hotword recognition
+ if (audioSession->activeCount() > 0 &&
+ ((audioSession->inputSource() == source) ||
+ ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
+ (audioSession->inputSource() == AUDIO_SOURCE_HOTWORD) &&
+ audioSession->isSoundTrigger()))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+status_t AudioSessionCollection::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+ snprintf(buffer, SIZE, "%*sAudio Sessions:\n", spaces, "");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ valueAt(i)->dump(fd, spaces + 2, i);
+ }
+ return NO_ERROR;
+}
+
+}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
new file mode 100644
index 0000000..ba33e57
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 89ef045..b187857 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -18,139 +18,242 @@
//#define LOG_NDEBUG 0
#include "ConfigParsingUtils.h"
+#include <convert/convert.h>
#include "AudioGain.h"
+#include "IOProfile.h"
+#include "TypeConverter.h"
#include <hardware/audio.h>
#include <utils/Log.h>
#include <cutils/misc.h>
namespace android {
-//static
-uint32_t ConfigParsingUtils::stringToEnum(const struct StringToEnum *table,
- size_t size,
- const char *name)
-{
- for (size_t i = 0; i < size; i++) {
- if (strcmp(table[i].name, name) == 0) {
- ALOGV("stringToEnum() found %s", table[i].name);
- return table[i].value;
- }
- }
- return 0;
-}
-
-//static
-const char *ConfigParsingUtils::enumToString(const struct StringToEnum *table,
- size_t size,
- uint32_t value)
-{
- for (size_t i = 0; i < size; i++) {
- if (table[i].value == value) {
- return table[i].name;
- }
- }
- return "";
-}
-
-//static
-bool ConfigParsingUtils::stringToBool(const char *value)
-{
- return ((strcasecmp("true", value) == 0) || (strcmp("1", value) == 0));
-}
-
-
// --- audio_policy.conf file parsing
//static
-uint32_t ConfigParsingUtils::parseOutputFlagNames(char *name)
+uint32_t ConfigParsingUtils::parseOutputFlagNames(const char *name)
{
- uint32_t flag = 0;
-
- // it is OK to cast name to non const here as we are not going to use it after
- // strtok() modifies it
- char *flagName = strtok(name, "|");
- while (flagName != NULL) {
- if (strlen(flagName) != 0) {
- flag |= ConfigParsingUtils::stringToEnum(sOutputFlagNameToEnumTable,
- ARRAY_SIZE(sOutputFlagNameToEnumTable),
- flagName);
- }
- flagName = strtok(NULL, "|");
- }
+ uint32_t flag = OutputFlagConverter::maskFromString(name);
//force direct flag if offload flag is set: offloading implies a direct output stream
// and all common behaviors are driven by checking only the direct flag
// this should normally be set appropriately in the policy configuration file
if ((flag & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
flag |= AUDIO_OUTPUT_FLAG_DIRECT;
}
-
return flag;
}
//static
-uint32_t ConfigParsingUtils::parseInputFlagNames(char *name)
+void ConfigParsingUtils::loadAudioPortGain(cnode *root, AudioPort &audioPort, int index)
{
- uint32_t flag = 0;
+ cnode *node = root->first_child;
- // it is OK to cast name to non const here as we are not going to use it after
- // strtok() modifies it
- char *flagName = strtok(name, "|");
- while (flagName != NULL) {
- if (strlen(flagName) != 0) {
- flag |= stringToEnum(sInputFlagNameToEnumTable,
- ARRAY_SIZE(sInputFlagNameToEnumTable),
- flagName);
+ sp<AudioGain> gain = new AudioGain(index, audioPort.useInputChannelMask());
+
+ while (node) {
+ if (strcmp(node->name, GAIN_MODE) == 0) {
+ gain->setMode(GainModeConverter::maskFromString(node->value));
+ } else if (strcmp(node->name, GAIN_CHANNELS) == 0) {
+ audio_channel_mask_t mask;
+ if (audioPort.useInputChannelMask()) {
+ if (InputChannelConverter::fromString(node->value, mask)) {
+ gain->setChannelMask(mask);
+ }
+ } else {
+ if (OutputChannelConverter::fromString(node->value, mask)) {
+ gain->setChannelMask(mask);
+ }
+ }
+ } else if (strcmp(node->name, GAIN_MIN_VALUE) == 0) {
+ gain->setMinValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_MAX_VALUE) == 0) {
+ gain->setMaxValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_DEFAULT_VALUE) == 0) {
+ gain->setDefaultValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_STEP_VALUE) == 0) {
+ gain->setStepValueInMb(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_MIN_RAMP_MS) == 0) {
+ gain->setMinRampInMs(atoi(node->value));
+ } else if (strcmp(node->name, GAIN_MAX_RAMP_MS) == 0) {
+ gain->setMaxRampInMs(atoi(node->value));
}
- flagName = strtok(NULL, "|");
+ node = node->next;
}
- return flag;
+
+ ALOGV("loadGain() adding new gain mode %08x channel mask %08x min mB %d max mB %d",
+ gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
+ gain->getMaxValueInMb());
+
+ if (gain->getMode() == 0) {
+ return;
+ }
+ audioPort.mGains.add(gain);
}
-//static
-audio_devices_t ConfigParsingUtils::parseDeviceNames(char *name)
+void ConfigParsingUtils::loadAudioPortGains(cnode *root, AudioPort &audioPort)
{
- uint32_t device = 0;
-
- char *devName = strtok(name, "|");
- while (devName != NULL) {
- if (strlen(devName) != 0) {
- device |= stringToEnum(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- devName);
- }
- devName = strtok(NULL, "|");
- }
- return device;
+ cnode *node = root->first_child;
+ int index = 0;
+ while (node) {
+ ALOGV("loadGains() loading gain %s", node->name);
+ loadAudioPortGain(node, audioPort, index++);
+ node = node->next;
+ }
}
//static
-void ConfigParsingUtils::loadHwModule(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnable)
+void ConfigParsingUtils::loadDeviceDescriptorGains(cnode *root, sp<DeviceDescriptor> &deviceDesc)
+{
+ loadAudioPortGains(root, *deviceDesc);
+ if (deviceDesc->mGains.size() > 0) {
+ deviceDesc->mGains[0]->getDefaultConfig(&deviceDesc->mGain);
+ }
+}
+
+//static
+status_t ConfigParsingUtils::loadHwModuleDevice(cnode *root, DeviceVector &devices)
+{
+ cnode *node = root->first_child;
+
+ audio_devices_t type = AUDIO_DEVICE_NONE;
+ while (node) {
+ if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
+ DeviceConverter::fromString(node->value, type);
+ break;
+ }
+ node = node->next;
+ }
+ if (type == AUDIO_DEVICE_NONE ||
+ (!audio_is_input_device(type) && !audio_is_output_device(type))) {
+ ALOGW("loadDevice() bad type %08x", type);
+ return BAD_VALUE;
+ }
+ sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type, String8(root->name));
+
+ node = root->first_child;
+ while (node) {
+ if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
+ deviceDesc->mAddress = String8((char *)node->value);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
+ if (audio_is_input_device(type)) {
+ deviceDesc->addAudioProfile(
+ new AudioProfile(gDynamicFormat,
+ inputChannelMasksFromString(node->value),
+ SampleRateVector()));
+ } else {
+ deviceDesc->addAudioProfile(
+ new AudioProfile(gDynamicFormat,
+ outputChannelMasksFromString(node->value),
+ SampleRateVector()));
+ }
+ } else if (strcmp(node->name, GAINS_TAG) == 0) {
+ loadDeviceDescriptorGains(node, deviceDesc);
+ }
+ node = node->next;
+ }
+
+ ALOGV("loadDevice() adding device tag (literal type) %s type %08x address %s",
+ deviceDesc->getTagName().string(), type, deviceDesc->mAddress.string());
+
+ devices.add(deviceDesc);
+ return NO_ERROR;
+}
+
+//static
+status_t ConfigParsingUtils::loadHwModuleProfile(cnode *root, sp<HwModule> &module,
+ audio_port_role_t role)
+{
+ cnode *node = root->first_child;
+
+ sp<IOProfile> profile = new IOProfile(String8(root->name), role);
+
+ AudioProfileVector audioProfiles;
+ SampleRateVector sampleRates;
+ ChannelsVector channels;
+ FormatVector formats;
+
+ while (node) {
+ if (strcmp(node->name, FORMATS_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ formats = formatsFromString(node->value);
+ } else if (strcmp(node->name, SAMPLING_RATES_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ collectionFromString<SampleRateTraits>(node->value, sampleRates);
+ } else if (strcmp(node->name, CHANNELS_TAG) == 0 &&
+ strcmp(node->value, DYNAMIC_VALUE_TAG) != 0) {
+ if (role == AUDIO_PORT_ROLE_SINK) {
+ channels = inputChannelMasksFromString(node->value);
+ } else {
+ channels = outputChannelMasksFromString(node->value);
+ }
+ } else if (strcmp(node->name, DEVICES_TAG) == 0) {
+ DeviceVector devices;
+ loadDevicesFromTag(node->value, devices, module->getDeclaredDevices());
+ profile->setSupportedDevices(devices);
+ } else if (strcmp(node->name, FLAGS_TAG) == 0) {
+ if (role == AUDIO_PORT_ROLE_SINK) {
+ profile->setFlags(InputFlagConverter::maskFromString(node->value));
+ } else {
+ profile->setFlags(ConfigParsingUtils::parseOutputFlagNames(node->value));
+ }
+ } else if (strcmp(node->name, GAINS_TAG) == 0) {
+ loadAudioPortGains(node, *profile);
+ }
+ node = node->next;
+ }
+ if (formats.isEmpty()) {
+ sp<AudioProfile> profileToAdd = new AudioProfile(gDynamicFormat, channels, sampleRates);
+ profileToAdd->setDynamicFormat(true);
+ profileToAdd->setDynamicChannels(channels.isEmpty());
+ profileToAdd->setDynamicRate(sampleRates.isEmpty());
+ audioProfiles.add(profileToAdd);
+ } else {
+ for (size_t i = 0; i < formats.size(); i++) {
+ // For compatibility reason, for each format, creates a profile with the same
+ // collection of rate and channels.
+ sp<AudioProfile> profileToAdd = new AudioProfile(formats[i], channels, sampleRates);
+ profileToAdd->setDynamicFormat(formats[i] == gDynamicFormat);
+ profileToAdd->setDynamicChannels(channels.isEmpty());
+ profileToAdd->setDynamicRate(sampleRates.isEmpty());
+ audioProfiles.add(profileToAdd);
+ }
+ }
+ profile->setAudioProfiles(audioProfiles);
+ ALOGW_IF(!profile->hasSupportedDevices(), "load%s() invalid supported devices",
+ role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output");
+ if (profile->hasSupportedDevices()) {
+ ALOGV("load%s() adding Supported Devices %04x, mFlags %04x",
+ role == AUDIO_PORT_ROLE_SINK ? "Input" : "Output",
+ profile->getSupportedDevicesType(), profile->getFlags());
+ return module->addProfile(profile);
+ }
+ return BAD_VALUE;
+}
+
+//static
+status_t ConfigParsingUtils::loadHwModule(cnode *root, sp<HwModule> &module,
+ AudioPolicyConfig &config)
{
status_t status = NAME_NOT_FOUND;
- cnode *node;
- sp<HwModule> module = new HwModule(root->name);
-
- node = config_find(root, DEVICES_TAG);
+ cnode *node = config_find(root, DEVICES_TAG);
if (node != NULL) {
node = node->first_child;
+ DeviceVector devices;
while (node) {
ALOGV("loadHwModule() loading device %s", node->name);
- status_t tmpStatus = module->loadDevice(node);
+ status_t tmpStatus = loadHwModuleDevice(node, devices);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
node = node->next;
}
+ module->setDeclaredDevices(devices);
}
node = config_find(root, OUTPUTS_TAG);
if (node != NULL) {
node = node->first_child;
while (node) {
ALOGV("loadHwModule() loading output %s", node->name);
- status_t tmpStatus = module->loadOutput(node);
+ status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SOURCE);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
@@ -162,27 +265,20 @@
node = node->first_child;
while (node) {
ALOGV("loadHwModule() loading input %s", node->name);
- status_t tmpStatus = module->loadInput(node);
+ status_t tmpStatus = loadHwModuleProfile(node, module, AUDIO_PORT_ROLE_SINK);
if (status == NAME_NOT_FOUND || status == NO_ERROR) {
status = tmpStatus;
}
node = node->next;
}
}
- loadGlobalConfig(root, module, availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnable);
-
- if (status == NO_ERROR) {
- hwModules.add(module);
- }
+ loadModuleGlobalConfig(root, module, config);
+ return status;
}
//static
void ConfigParsingUtils::loadHwModules(cnode *root, HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled)
+ AudioPolicyConfig &config)
{
cnode *node = config_find(root, AUDIO_HW_MODULE_TAG);
if (node == NULL) {
@@ -192,18 +288,42 @@
node = node->first_child;
while (node) {
ALOGV("loadHwModules() loading module %s", node->name);
- loadHwModule(node, hwModules, availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnabled);
+ sp<HwModule> module = new HwModule(node->name);
+ if (loadHwModule(node, module, config) == NO_ERROR) {
+ hwModules.add(module);
+ }
node = node->next;
}
}
//static
-void ConfigParsingUtils::loadGlobalConfig(cnode *root, const sp<HwModule>& module,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevice,
- bool &speakerDrcEnabled)
+void ConfigParsingUtils::loadDevicesFromTag(const char *tag, DeviceVector &devices,
+ const DeviceVector &declaredDevices)
+{
+ char *tagLiteral = strndup(tag, strlen(tag));
+ char *devTag = strtok(tagLiteral, "|");
+ while (devTag != NULL) {
+ if (strlen(devTag) != 0) {
+ audio_devices_t type;
+ if (DeviceConverter::fromString(devTag, type)) {
+ sp<DeviceDescriptor> dev = new DeviceDescriptor(type);
+ devices.add(dev);
+ } else {
+ sp<DeviceDescriptor> deviceDesc =
+ declaredDevices.getDeviceFromTagName(String8(devTag));
+ if (deviceDesc != 0) {
+ devices.add(deviceDesc);
+ }
+ }
+ }
+ devTag = strtok(NULL, "|");
+ }
+ free(tagLiteral);
+}
+
+//static
+void ConfigParsingUtils::loadModuleGlobalConfig(cnode *root, const sp<HwModule> &module,
+ AudioPolicyConfig &config)
{
cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
@@ -212,52 +332,68 @@
}
DeviceVector declaredDevices;
if (module != NULL) {
- declaredDevices = module->mDeclaredDevices;
+ declaredDevices = module->getDeclaredDevices();
}
node = node->first_child;
while (node) {
if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
- availableOutputDevices.loadDevicesFromTag((char *)node->value,
- declaredDevices);
+ DeviceVector availableOutputDevices;
+ loadDevicesFromTag(node->value, availableOutputDevices, declaredDevices);
ALOGV("loadGlobalConfig() Attached Output Devices %08x",
availableOutputDevices.types());
+ config.addAvailableOutputDevices(availableOutputDevices);
} else if (strcmp(DEFAULT_OUTPUT_DEVICE_TAG, node->name) == 0) {
- audio_devices_t device = (audio_devices_t)stringToEnum(
- sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- (char *)node->value);
+ audio_devices_t device = AUDIO_DEVICE_NONE;
+ DeviceConverter::fromString(node->value, device);
if (device != AUDIO_DEVICE_NONE) {
- defaultOutputDevice = new DeviceDescriptor(device);
+ sp<DeviceDescriptor> defaultOutputDevice = new DeviceDescriptor(device);
+ config.setDefaultOutputDevice(defaultOutputDevice);
+ ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
} else {
ALOGW("loadGlobalConfig() default device not specified");
}
- ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
- availableInputDevices.loadDevicesFromTag((char *)node->value,
- declaredDevices);
+ DeviceVector availableInputDevices;
+ loadDevicesFromTag(node->value, availableInputDevices, declaredDevices);
ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
- } else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
- speakerDrcEnabled = stringToBool((char *)node->value);
- ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
+ config.addAvailableInputDevices(availableInputDevices);
} else if (strcmp(AUDIO_HAL_VERSION_TAG, node->name) == 0) {
uint32_t major, minor;
sscanf((char *)node->value, "%u.%u", &major, &minor);
- module->mHalVersion = HARDWARE_DEVICE_API_VERSION(major, minor);
+ module->setHalVersion(HARDWARE_DEVICE_API_VERSION(major, minor));
ALOGV("loadGlobalConfig() mHalVersion = %04x major %u minor %u",
- module->mHalVersion, major, minor);
+ module->getHalVersion(), major, minor);
}
node = node->next;
}
}
//static
-status_t ConfigParsingUtils::loadAudioPolicyConfig(const char *path,
- HwModuleCollection &hwModules,
- DeviceVector &availableInputDevices,
- DeviceVector &availableOutputDevices,
- sp<DeviceDescriptor> &defaultOutputDevices,
- bool &isSpeakerDrcEnabled)
+void ConfigParsingUtils::loadGlobalConfig(cnode *root, AudioPolicyConfig &config,
+ const sp<HwModule>& primaryModule)
+{
+ cnode *node = config_find(root, GLOBAL_CONFIG_TAG);
+
+ if (node == NULL) {
+ return;
+ }
+ node = node->first_child;
+ while (node) {
+ if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
+ bool speakerDrcEnabled;
+ if (utilities::convertTo<std::string, bool>(node->value, speakerDrcEnabled)) {
+ ALOGV("loadGlobalConfig() mSpeakerDrcEnabled = %d", speakerDrcEnabled);
+ config.setSpeakerDrcEnabled(speakerDrcEnabled);
+ }
+ }
+ node = node->next;
+ }
+ loadModuleGlobalConfig(root, primaryModule, config);
+}
+
+//static
+status_t ConfigParsingUtils::loadConfig(const char *path, AudioPolicyConfig &config)
{
cnode *root;
char *data;
@@ -269,13 +405,14 @@
root = config_node("", "");
config_load(root, data);
- loadHwModules(root, hwModules,
- availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnabled);
- // legacy audio_policy.conf files have one global_configuration section
- loadGlobalConfig(root, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY),
- availableInputDevices, availableOutputDevices,
- defaultOutputDevices, isSpeakerDrcEnabled);
+ HwModuleCollection hwModules;
+ loadHwModules(root, hwModules, config);
+
+ // legacy audio_policy.conf files have one global_configuration section, attached to primary.
+ loadGlobalConfig(root, config, hwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY));
+
+ config.setHwModules(hwModules);
+
config_free(root);
free(root);
free(data);
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 1f1fca3..538876c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -18,19 +18,21 @@
//#define LOG_NDEBUG 0
#include "DeviceDescriptor.h"
+#include "TypeConverter.h"
#include "AudioGain.h"
#include "HwModule.h"
-#include "ConfigParsingUtils.h"
namespace android {
-DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type, const String8 &tagName) :
AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
AUDIO_PORT_ROLE_SOURCE),
- mTag(""), mAddress(""), mDeviceType(type), mId(0)
+ mAddress(""), mTagName(tagName), mDeviceType(type), mId(0)
{
-
+ if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX || type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
+ mAddress = String8("0");
+ }
}
audio_port_handle_t DeviceDescriptor::getId() const
@@ -59,14 +61,6 @@
mChannelMask == other->mChannelMask);
}
-void DeviceDescriptor::loadGains(cnode *root)
-{
- AudioPort::loadGains(root);
- if (mGains.size() > 0) {
- mGains[0]->getDefaultConfig(&mGain);
- }
-}
-
void DeviceVector::refreshTypes()
{
mDeviceTypes = AUDIO_DEVICE_NONE;
@@ -86,6 +80,16 @@
return -1;
}
+void DeviceVector::add(const DeviceVector &devices)
+{
+ for (size_t i = 0; i < devices.size(); i++) {
+ sp<DeviceDescriptor> device = devices.itemAt(i);
+ if (indexOf(device) < 0 && SortedVector::add(device) >= 0) {
+ refreshTypes();
+ }
+ }
+}
+
ssize_t DeviceVector::add(const sp<DeviceDescriptor>& item)
{
ssize_t ret = indexOf(item);
@@ -129,49 +133,6 @@
return devices;
}
-void DeviceVector::loadDevicesFromType(audio_devices_t types)
-{
- DeviceVector deviceList;
-
- uint32_t role_bit = AUDIO_DEVICE_BIT_IN & types;
- types &= ~role_bit;
-
- while (types) {
- uint32_t i = 31 - __builtin_clz(types);
- uint32_t type = 1 << i;
- types &= ~type;
- add(new DeviceDescriptor(type | role_bit));
- }
-}
-
-void DeviceVector::loadDevicesFromTag(char *tag,
- const DeviceVector& declaredDevices)
-{
- char *devTag = strtok(tag, "|");
- while (devTag != NULL) {
- if (strlen(devTag) != 0) {
- audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- devTag);
- if (type != AUDIO_DEVICE_NONE) {
- sp<DeviceDescriptor> dev = new DeviceDescriptor(type);
- if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
- type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
- dev->mAddress = String8("0");
- }
- add(dev);
- } else {
- sp<DeviceDescriptor> deviceDesc =
- declaredDevices.getDeviceFromTag(String8(devTag));
- if (deviceDesc != 0) {
- add(deviceDesc);
- }
- }
- }
- devTag = strtok(NULL, "|");
- }
-}
-
sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, String8 address) const
{
sp<DeviceDescriptor> device;
@@ -234,11 +195,11 @@
return devices;
}
-sp<DeviceDescriptor> DeviceVector::getDeviceFromTag(const String8& tag) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTagName(const String8 &tagName) const
{
sp<DeviceDescriptor> device;
for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mTag == tag) {
+ if (itemAt(i)->getTagName() == tagName) {
device = itemAt(i);
break;
}
@@ -246,16 +207,18 @@
return device;
}
-
-status_t DeviceVector::dump(int fd, const String8 &direction) const
+status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
{
+ if (isEmpty()) {
+ return NO_ERROR;
+ }
const size_t SIZE = 256;
char buffer[SIZE];
- snprintf(buffer, SIZE, "\n Available %s devices:\n", direction.string());
+ snprintf(buffer, SIZE, "%*s %s devices:\n", spaces, "", tag.string());
write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < size(); i++) {
- itemAt(i)->dump(fd, 2, i);
+ itemAt(i)->dump(fd, spaces + 4, i, verbose);
}
return NO_ERROR;
}
@@ -303,12 +266,10 @@
void DeviceDescriptor::importAudioPort(const sp<AudioPort> port) {
AudioPort::importAudioPort(port);
- mSamplingRate = port->pickSamplingRate();
- mFormat = port->pickFormat();
- mChannelMask = port->pickChannelMask();
+ port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
}
-status_t DeviceDescriptor::dump(int fd, int spaces, int index) const
+status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
{
const size_t SIZE = 256;
char buffer[SIZE];
@@ -320,28 +281,30 @@
snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
result.append(buffer);
}
- snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "",
- ConfigParsingUtils::enumToString(sDeviceTypeToEnumTable,
- ARRAY_SIZE(sDeviceTypeToEnumTable),
- mDeviceType));
- result.append(buffer);
+ if (!mTagName.isEmpty()) {
+ snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
+ result.append(buffer);
+ }
+ std::string deviceLiteral;
+ if (DeviceConverter::toString(mDeviceType, deviceLiteral)) {
+ snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
+ result.append(buffer);
+ }
if (mAddress.size() != 0) {
snprintf(buffer, SIZE, "%*s- address: %-32s\n", spaces, "", mAddress.string());
result.append(buffer);
}
write(fd, result.string(), result.size());
- AudioPort::dump(fd, spaces);
+ AudioPort::dump(fd, spaces, verbose);
return NO_ERROR;
}
void DeviceDescriptor::log() const
{
- ALOGI("Device id:%d type:0x%X:%s, addr:%s",
- mId,
- mDeviceType,
- ConfigParsingUtils::enumToString(
- sDeviceNameToEnumTable, ARRAY_SIZE(sDeviceNameToEnumTable), mDeviceType),
+ std::string device;
+ DeviceConverter::toString(mDeviceType, device);
+ ALOGI("Device id:%d type:0x%X:%s, addr:%s", mId, mDeviceType, device.c_str(),
mAddress.string());
AudioPort::log(" ");
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index 7e2050b..93ab9c7 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -20,190 +20,83 @@
#include "HwModule.h"
#include "IOProfile.h"
#include "AudioGain.h"
-#include "ConfigParsingUtils.h"
-#include "audio_policy_conf.h"
#include <hardware/audio.h>
#include <policy.h>
namespace android {
-HwModule::HwModule(const char *name)
- : mName(strndup(name, AUDIO_HARDWARE_MODULE_ID_MAX_LEN)),
- mHalVersion(AUDIO_DEVICE_API_VERSION_MIN), mHandle(0)
+HwModule::HwModule(const char *name, uint32_t halVersion)
+ : mName(String8(name)),
+ mHandle(0),
+ mHalVersion(halVersion)
{
}
HwModule::~HwModule()
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- mOutputProfiles[i]->mSupportedDevices.clear();
+ mOutputProfiles[i]->clearSupportedDevices();
}
for (size_t i = 0; i < mInputProfiles.size(); i++) {
- mInputProfiles[i]->mSupportedDevices.clear();
+ mInputProfiles[i]->clearSupportedDevices();
}
- free((void *)mName);
-}
-
-status_t HwModule::loadInput(cnode *root)
-{
- cnode *node = root->first_child;
-
- sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SINK);
-
- while (node) {
- if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- profile->loadSamplingRates((char *)node->value);
- } else if (strcmp(node->name, FORMATS_TAG) == 0) {
- profile->loadFormats((char *)node->value);
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- profile->loadInChannels((char *)node->value);
- } else if (strcmp(node->name, DEVICES_TAG) == 0) {
- profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
- mDeclaredDevices);
- } else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->mFlags = ConfigParsingUtils::parseInputFlagNames((char *)node->value);
- } else if (strcmp(node->name, GAINS_TAG) == 0) {
- profile->loadGains(node);
- }
- node = node->next;
- }
- ALOGW_IF(profile->mSupportedDevices.isEmpty(),
- "loadInput() invalid supported devices");
- ALOGW_IF(profile->mChannelMasks.size() == 0,
- "loadInput() invalid supported channel masks");
- ALOGW_IF(profile->mSamplingRates.size() == 0,
- "loadInput() invalid supported sampling rates");
- ALOGW_IF(profile->mFormats.size() == 0,
- "loadInput() invalid supported formats");
- if (!profile->mSupportedDevices.isEmpty() &&
- (profile->mChannelMasks.size() != 0) &&
- (profile->mSamplingRates.size() != 0) &&
- (profile->mFormats.size() != 0)) {
-
- ALOGV("loadInput() adding input Supported Devices %04x",
- profile->mSupportedDevices.types());
-
- profile->attach(this);
- mInputProfiles.add(profile);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t HwModule::loadOutput(cnode *root)
-{
- cnode *node = root->first_child;
-
- sp<IOProfile> profile = new IOProfile(String8(root->name), AUDIO_PORT_ROLE_SOURCE);
-
- while (node) {
- if (strcmp(node->name, SAMPLING_RATES_TAG) == 0) {
- profile->loadSamplingRates((char *)node->value);
- } else if (strcmp(node->name, FORMATS_TAG) == 0) {
- profile->loadFormats((char *)node->value);
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- profile->loadOutChannels((char *)node->value);
- } else if (strcmp(node->name, DEVICES_TAG) == 0) {
- profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
- mDeclaredDevices);
- } else if (strcmp(node->name, FLAGS_TAG) == 0) {
- profile->mFlags = ConfigParsingUtils::parseOutputFlagNames((char *)node->value);
- } else if (strcmp(node->name, GAINS_TAG) == 0) {
- profile->loadGains(node);
- }
- node = node->next;
- }
- ALOGW_IF(profile->mSupportedDevices.isEmpty(),
- "loadOutput() invalid supported devices");
- ALOGW_IF(profile->mChannelMasks.size() == 0,
- "loadOutput() invalid supported channel masks");
- ALOGW_IF(profile->mSamplingRates.size() == 0,
- "loadOutput() invalid supported sampling rates");
- ALOGW_IF(profile->mFormats.size() == 0,
- "loadOutput() invalid supported formats");
- if (!profile->mSupportedDevices.isEmpty() &&
- (profile->mChannelMasks.size() != 0) &&
- (profile->mSamplingRates.size() != 0) &&
- (profile->mFormats.size() != 0)) {
-
- ALOGV("loadOutput() adding output Supported Devices %04x, mFlags %04x",
- profile->mSupportedDevices.types(), profile->mFlags);
- profile->attach(this);
- mOutputProfiles.add(profile);
- return NO_ERROR;
- } else {
- return BAD_VALUE;
- }
-}
-
-status_t HwModule::loadDevice(cnode *root)
-{
- cnode *node = root->first_child;
-
- audio_devices_t type = AUDIO_DEVICE_NONE;
- while (node) {
- if (strcmp(node->name, APM_DEVICE_TYPE) == 0) {
- type = ConfigParsingUtils::parseDeviceNames((char *)node->value);
- break;
- }
- node = node->next;
- }
- if (type == AUDIO_DEVICE_NONE ||
- (!audio_is_input_device(type) && !audio_is_output_device(type))) {
- ALOGW("loadDevice() bad type %08x", type);
- return BAD_VALUE;
- }
- sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type);
- deviceDesc->mTag = String8(root->name);
-
- node = root->first_child;
- while (node) {
- if (strcmp(node->name, APM_DEVICE_ADDRESS) == 0) {
- deviceDesc->mAddress = String8((char *)node->value);
- } else if (strcmp(node->name, CHANNELS_TAG) == 0) {
- if (audio_is_input_device(type)) {
- deviceDesc->loadInChannels((char *)node->value);
- } else {
- deviceDesc->loadOutChannels((char *)node->value);
- }
- } else if (strcmp(node->name, GAINS_TAG) == 0) {
- deviceDesc->loadGains(node);
- }
- node = node->next;
- }
-
- ALOGV("loadDevice() adding device tag %s type %08x address %s",
- deviceDesc->mTag.string(), type, deviceDesc->mAddress.string());
-
- mDeclaredDevices.add(deviceDesc);
-
- return NO_ERROR;
}
status_t HwModule::addOutputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
+ audio_devices_t device, String8 address)
{
- sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SOURCE);
+ sp<IOProfile> profile = new OutputProfile(name);
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
+ profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+ config->sample_rate));
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
- profile->mSupportedDevices.add(devDesc);
+ profile->addSupportedDevice(devDesc);
+ return addOutputProfile(profile);
+}
+
+status_t HwModule::addOutputProfile(const sp<IOProfile> &profile)
+{
profile->attach(this);
mOutputProfiles.add(profile);
-
+ mPorts.add(profile);
return NO_ERROR;
}
+status_t HwModule::addInputProfile(const sp<IOProfile> &profile)
+{
+ profile->attach(this);
+ mInputProfiles.add(profile);
+ mPorts.add(profile);
+ return NO_ERROR;
+}
+
+status_t HwModule::addProfile(const sp<IOProfile> &profile)
+{
+ switch (profile->getRole()) {
+ case AUDIO_PORT_ROLE_SOURCE:
+ return addOutputProfile(profile);
+ case AUDIO_PORT_ROLE_SINK:
+ return addInputProfile(profile);
+ case AUDIO_PORT_ROLE_NONE:
+ return BAD_VALUE;
+ }
+ return BAD_VALUE;
+}
+
+void HwModule::setProfiles(const IOProfileCollection &profiles)
+{
+ for (size_t i = 0; i < profiles.size(); i++) {
+ addProfile(profiles[i]);
+ }
+}
+
status_t HwModule::removeOutputProfile(String8 name)
{
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- if (mOutputProfiles[i]->mName == name) {
+ if (mOutputProfiles[i]->getName() == name) {
mOutputProfiles.removeAt(i);
break;
}
@@ -213,30 +106,26 @@
}
status_t HwModule::addInputProfile(String8 name, const audio_config_t *config,
- audio_devices_t device, String8 address)
+ audio_devices_t device, String8 address)
{
- sp<IOProfile> profile = new IOProfile(name, AUDIO_PORT_ROLE_SINK);
-
- profile->mSamplingRates.add(config->sample_rate);
- profile->mChannelMasks.add(config->channel_mask);
- profile->mFormats.add(config->format);
+ sp<IOProfile> profile = new InputProfile(name);
+ profile->addAudioProfile(new AudioProfile(config->format, config->channel_mask,
+ config->sample_rate));
sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
- profile->mSupportedDevices.add(devDesc);
+ profile->addSupportedDevice(devDesc);
- ALOGV("addInputProfile() name %s rate %d mask 0x08", name.string(), config->sample_rate, config->channel_mask);
+ ALOGV("addInputProfile() name %s rate %d mask 0x%08x",
+ name.string(), config->sample_rate, config->channel_mask);
- profile->attach(this);
- mInputProfiles.add(profile);
-
- return NO_ERROR;
+ return addInputProfile(profile);
}
status_t HwModule::removeInputProfile(String8 name)
{
for (size_t i = 0; i < mInputProfiles.size(); i++) {
- if (mInputProfiles[i]->mName == name) {
+ if (mInputProfiles[i]->getName() == name) {
mInputProfiles.removeAt(i);
break;
}
@@ -245,6 +134,88 @@
return NO_ERROR;
}
+void HwModule::setDeclaredDevices(const DeviceVector &devices)
+{
+ mDeclaredDevices = devices;
+ for (size_t i = 0; i < devices.size(); i++) {
+ mPorts.add(devices[i]);
+ }
+}
+
+sp<DeviceDescriptor> HwModule::getRouteSinkDevice(const sp<AudioRoute> &route) const
+{
+ sp<DeviceDescriptor> sinkDevice = 0;
+ if (route->getSink()->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ sinkDevice = mDeclaredDevices.getDeviceFromTagName(route->getSink()->getTagName());
+ }
+ return sinkDevice;
+}
+
+DeviceVector HwModule::getRouteSourceDevices(const sp<AudioRoute> &route) const
+{
+ DeviceVector sourceDevices;
+ Vector <sp<AudioPort> > sources = route->getSources();
+ for (size_t i = 0; i < sources.size(); i++) {
+ if (sources[i]->getType() == AUDIO_PORT_TYPE_DEVICE) {
+ sourceDevices.add(mDeclaredDevices.getDeviceFromTagName(sources[i]->getTagName()));
+ }
+ }
+ return sourceDevices;
+}
+
+void HwModule::setRoutes(const AudioRouteVector &routes)
+{
+ mRoutes = routes;
+ // Now updating the streams (aka IOProfile until now) supported devices
+ refreshSupportedDevices();
+}
+
+void HwModule::refreshSupportedDevices()
+{
+ // Now updating the streams (aka IOProfile until now) supported devices
+ for (size_t i = 0; i < mInputProfiles.size(); i++) {
+ sp<IOProfile> stream = mInputProfiles[i];
+ DeviceVector sourceDevices;
+ const AudioRouteVector &routes = stream->getRoutes();
+ for (size_t j = 0; j < routes.size(); j++) {
+ sp<AudioPort> sink = routes[j]->getSink();
+ if (sink == 0 || stream != sink) {
+ ALOGE("%s: Invalid route attached to input stream", __FUNCTION__);
+ continue;
+ }
+ DeviceVector sourceDevicesForRoute = getRouteSourceDevices(routes[j]);
+ if (sourceDevicesForRoute.isEmpty()) {
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ sourceDevices.add(sourceDevicesForRoute);
+ }
+ if (sourceDevices.isEmpty()) {
+ ALOGE("%s: invalid source devices for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ stream->setSupportedDevices(sourceDevices);
+ }
+ for (size_t i = 0; i < mOutputProfiles.size(); i++) {
+ sp<IOProfile> stream = mOutputProfiles[i];
+ DeviceVector sinkDevices;
+ const AudioRouteVector &routes = stream->getRoutes();
+ for (size_t j = 0; j < routes.size(); j++) {
+ sp<AudioPort> source = routes[j]->getSources().findByTagName(stream->getTagName());
+ if (source == 0 || stream != source) {
+ ALOGE("%s: Invalid route attached to output stream", __FUNCTION__);
+ continue;
+ }
+ sp<DeviceDescriptor> sinkDevice = getRouteSinkDevice(routes[j]);
+ if (sinkDevice == 0) {
+ ALOGE("%s: invalid sink device for %s", __FUNCTION__, stream->getName().string());
+ continue;
+ }
+ sinkDevices.add(sinkDevice);
+ }
+ stream->setSupportedDevices(sinkDevices);
+ }
+}
void HwModule::dump(int fd)
{
@@ -252,7 +223,7 @@
char buffer[SIZE];
String8 result;
- snprintf(buffer, SIZE, " - name: %s\n", mName);
+ snprintf(buffer, SIZE, " - name: %s\n", getName());
result.append(buffer);
snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
result.append(buffer);
@@ -275,11 +246,10 @@
mInputProfiles[i]->dump(fd);
}
}
- if (mDeclaredDevices.size()) {
- write(fd, " - devices:\n", strlen(" - devices:\n"));
- for (size_t i = 0; i < mDeclaredDevices.size(); i++) {
- mDeclaredDevices[i]->dump(fd, 4, i);
- }
+ mDeclaredDevices.dump(fd, String8("Declared"), 2, true);
+ if (!mRoutes.empty()) {
+ write(fd, " - Audio Route:\n", strlen(" - Audio Route:\n"));
+ mRoutes.dump(fd);
}
}
@@ -289,7 +259,7 @@
for (size_t i = 0; i < size(); i++)
{
- if (strcmp(itemAt(i)->mName, name) == 0) {
+ if (strcmp(itemAt(i)->getName(), name) == 0) {
return itemAt(i);
}
}
@@ -302,20 +272,19 @@
sp <HwModule> module;
for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mHandle == 0) {
+ if (itemAt(i)->getHandle() == 0) {
continue;
}
if (audio_is_output_device(device)) {
for (size_t j = 0; j < itemAt(i)->mOutputProfiles.size(); j++)
{
- if (itemAt(i)->mOutputProfiles[j]->mSupportedDevices.types() & device) {
+ if (itemAt(i)->mOutputProfiles[j]->supportDevice(device)) {
return itemAt(i);
}
}
} else {
for (size_t j = 0; j < itemAt(i)->mInputProfiles.size(); j++) {
- if (itemAt(i)->mInputProfiles[j]->mSupportedDevices.types() &
- device & ~AUDIO_DEVICE_BIT_IN) {
+ if (itemAt(i)->mInputProfiles[j]->supportDevice(device)) {
return itemAt(i);
}
}
@@ -340,19 +309,18 @@
continue;
}
DeviceVector deviceList =
- hwModule->mDeclaredDevices.getDevicesFromTypeAddr(device, address);
+ hwModule->getDeclaredDevices().getDevicesFromTypeAddr(device, address);
if (!deviceList.isEmpty()) {
return deviceList.itemAt(0);
}
- deviceList = hwModule->mDeclaredDevices.getDevicesFromType(device);
+ deviceList = hwModule->getDeclaredDevices().getDevicesFromType(device);
if (!deviceList.isEmpty()) {
return deviceList.itemAt(0);
}
}
- sp<DeviceDescriptor> devDesc =
- new DeviceDescriptor(device);
- devDesc->mName = device_name;
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
+ devDesc->setName(String8(device_name));
devDesc->mAddress = address;
return devDesc;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index 7b6d51d..6e0a071 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -20,18 +20,10 @@
#include "IOProfile.h"
#include "HwModule.h"
#include "AudioGain.h"
+#include "TypeConverter.h"
namespace android {
-IOProfile::IOProfile(const String8& name, audio_port_role_t role)
- : AudioPort(name, AUDIO_PORT_TYPE_MIX, role)
-{
-}
-
-IOProfile::~IOProfile()
-{
-}
-
// checks if the IO profile is compatible with specified parameters.
// Sampling rate, format and channel mask must be specified in order to
// get a valid a match
@@ -45,8 +37,10 @@
audio_channel_mask_t *updatedChannelMask,
uint32_t flags) const
{
- const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
- const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
+ const bool isPlaybackThread =
+ getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SOURCE;
+ const bool isRecordThread =
+ getType() == AUDIO_PORT_TYPE_MIX && getRole() == AUDIO_PORT_ROLE_SINK;
ALOG_ASSERT(isPlaybackThread != isRecordThread);
@@ -61,47 +55,35 @@
}
}
- if (samplingRate == 0) {
- return false;
- }
- uint32_t myUpdatedSamplingRate = samplingRate;
- if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
- return false;
- }
- if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
- NO_ERROR) {
+ if (samplingRate == 0 || !audio_is_valid_format(format) ||
+ (isPlaybackThread && (!audio_is_output_channel(channelMask))) ||
+ (isRecordThread && (!audio_is_input_channel(channelMask)))) {
return false;
}
- if (!audio_is_valid_format(format)) {
- return false;
- }
- if (isPlaybackThread && checkExactFormat(format) != NO_ERROR) {
- return false;
- }
audio_format_t myUpdatedFormat = format;
- if (isRecordThread && checkCompatibleFormat(format, &myUpdatedFormat) != NO_ERROR) {
- return false;
- }
-
- if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
- checkExactChannelMask(channelMask) != NO_ERROR)) {
- return false;
- }
audio_channel_mask_t myUpdatedChannelMask = channelMask;
- if (isRecordThread && (!audio_is_input_channel(channelMask) ||
- checkCompatibleChannelMask(channelMask, &myUpdatedChannelMask) != NO_ERROR)) {
- return false;
+ uint32_t myUpdatedSamplingRate = samplingRate;
+ if (isRecordThread)
+ {
+ if (checkCompatibleAudioProfile(
+ myUpdatedSamplingRate, myUpdatedChannelMask, myUpdatedFormat) != NO_ERROR) {
+ return false;
+ }
+ } else {
+ if (checkExactAudioProfile(samplingRate, channelMask, format) != NO_ERROR) {
+ return false;
+ }
}
- if (isPlaybackThread && (mFlags & flags) != flags) {
+ if (isPlaybackThread && (getFlags() & flags) != flags) {
return false;
}
// The only input flag that is allowed to be different is the fast flag.
// An existing fast stream is compatible with a normal track request.
// An existing normal stream is compatible with a fast track request,
// but the fast request will be denied by AudioFlinger and converted to normal track.
- if (isRecordThread && ((mFlags ^ flags) &
+ if (isRecordThread && ((getFlags() ^ flags) &
~AUDIO_INPUT_FLAG_FAST)) {
return false;
}
@@ -126,39 +108,15 @@
AudioPort::dump(fd, 4);
- snprintf(buffer, SIZE, " - flags: 0x%04x\n", mFlags);
- result.append(buffer);
- snprintf(buffer, SIZE, " - devices:\n");
+ snprintf(buffer, SIZE, " - flags: 0x%04x\n", getFlags());
result.append(buffer);
write(fd, result.string(), result.size());
- for (size_t i = 0; i < mSupportedDevices.size(); i++) {
- mSupportedDevices[i]->dump(fd, 6, i);
- }
+ mSupportedDevices.dump(fd, String8("- Supported"), 2, false);
}
void IOProfile::log()
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- ALOGV(" - sampling rates: ");
- for (size_t i = 0; i < mSamplingRates.size(); i++) {
- ALOGV(" %d", mSamplingRates[i]);
- }
-
- ALOGV(" - channel masks: ");
- for (size_t i = 0; i < mChannelMasks.size(); i++) {
- ALOGV(" 0x%04x", mChannelMasks[i]);
- }
-
- ALOGV(" - formats: ");
- for (size_t i = 0; i < mFormats.size(); i++) {
- ALOGV(" 0x%08x", mFormats[i]);
- }
-
- ALOGV(" - devices: 0x%04x\n", mSupportedDevices.types());
- ALOGV(" - flags: 0x%04x\n", mFlags);
+ // @TODO: forward log to AudioPort
}
}; // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
index 4ca27c2..12c7930 100644
--- a/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/StreamDescriptor.cpp
@@ -71,7 +71,7 @@
mIndexMax = volIndexMax;
}
-void StreamDescriptor::setVolumeCurvePoint(Volume::device_category deviceCategory,
+void StreamDescriptor::setVolumeCurvePoint(device_category deviceCategory,
const VolumeCurvePoint *point)
{
mVolumeCurve[deviceCategory] = point;
@@ -121,14 +121,14 @@
}
void StreamDescriptorCollection::setVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory,
+ device_category deviceCategory,
const VolumeCurvePoint *point)
{
editValueAt(stream).setVolumeCurvePoint(deviceCategory, point);
}
const VolumeCurvePoint *StreamDescriptorCollection::getVolumeCurvePoint(audio_stream_type_t stream,
- Volume::device_category deviceCategory) const
+ device_category deviceCategory) const
{
return valueAt(stream).getVolumeCurvePoint(deviceCategory);
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
new file mode 100644
index 0000000..74d8809
--- /dev/null
+++ b/services/audiopolicy/common/managerdefinitions/src/TypeConverter.cpp
@@ -0,0 +1,297 @@
+/*
+ * 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.
+ */
+
+#include "TypeConverter.h"
+
+namespace android {
+
+#define MAKE_STRING_FROM_ENUM(string) { #string, string }
+
+template <>
+const DeviceConverter::Table DeviceConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_EARPIECE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPEAKER_SAFE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_WIRED_HEADPHONE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_DIGITAL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_ACCESSORY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_USB_DEVICE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_ALL_USB),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_REMOTE_SUBMIX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_TELEPHONY_TX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_HDMI_ARC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_SPDIF),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_FM),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_AUX_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_OUT_IP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AMBIENT),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BUILTIN_MIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ALL_SCO),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_WIRED_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_AUX_DIGITAL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_HDMI),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TELEPHONY_RX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_VOICE_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BACK_MIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_REMOTE_SUBMIX),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_ACCESSORY),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_USB_DEVICE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_FM_TUNER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_TV_TUNER),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LINE),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_SPDIF),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_BLUETOOTH_A2DP),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_LOOPBACK),
+ MAKE_STRING_FROM_ENUM(AUDIO_DEVICE_IN_IP),
+};
+
+template<>
+const size_t DeviceConverter::mSize = sizeof(DeviceConverter::mTable) /
+ sizeof(DeviceConverter::mTable[0]);
+
+
+template <>
+const OutputFlagConverter::Table OutputFlagConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DIRECT),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_PRIMARY),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_FAST),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_DEEP_BUFFER),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_NON_BLOCKING),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_HW_AV_SYNC),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_TTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_RAW),
+ MAKE_STRING_FROM_ENUM(AUDIO_OUTPUT_FLAG_SYNC),
+};
+template<>
+const size_t OutputFlagConverter::mSize = sizeof(OutputFlagConverter::mTable) /
+ sizeof(OutputFlagConverter::mTable[0]);
+
+
+template <>
+const InputFlagConverter::Table InputFlagConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_FAST),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_HW_HOTWORD),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_RAW),
+ MAKE_STRING_FROM_ENUM(AUDIO_INPUT_FLAG_SYNC),
+};
+template<>
+const size_t InputFlagConverter::mSize = sizeof(InputFlagConverter::mTable) /
+ sizeof(InputFlagConverter::mTable[0]);
+
+
+template <>
+const FormatConverter::Table FormatConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_16_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_32_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_8_24_BIT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_FLOAT),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_MP3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_MAIN),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SSR),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LTP),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_SCALABLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ERLC),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_LD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_HE_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AAC_ELD),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_VORBIS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V1),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_HE_AAC_V2),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_OPUS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_AC3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_E_AC3),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_FORMAT_DTS_HD),
+};
+template<>
+const size_t FormatConverter::mSize = sizeof(FormatConverter::mTable) /
+ sizeof(FormatConverter::mTable[0]);
+
+
+template <>
+const OutputChannelConverter::Table OutputChannelConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_STEREO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_QUAD),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
+};
+template<>
+const size_t OutputChannelConverter::mSize = sizeof(OutputChannelConverter::mTable) /
+ sizeof(OutputChannelConverter::mTable[0]);
+
+
+template <>
+const InputChannelConverter::Table InputChannelConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_MONO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_STEREO),
+ MAKE_STRING_FROM_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
+};
+template<>
+const size_t InputChannelConverter::mSize = sizeof(InputChannelConverter::mTable) /
+ sizeof(InputChannelConverter::mTable[0]);
+
+template <>
+const ChannelIndexConverter::Table ChannelIndexConverter::mTable[] = {
+ {"AUDIO_CHANNEL_INDEX_MASK_1", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_1)},
+ {"AUDIO_CHANNEL_INDEX_MASK_2", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_2)},
+ {"AUDIO_CHANNEL_INDEX_MASK_3", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_3)},
+ {"AUDIO_CHANNEL_INDEX_MASK_4", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_4)},
+ {"AUDIO_CHANNEL_INDEX_MASK_5", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_5)},
+ {"AUDIO_CHANNEL_INDEX_MASK_6", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_6)},
+ {"AUDIO_CHANNEL_INDEX_MASK_7", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_7)},
+ {"AUDIO_CHANNEL_INDEX_MASK_8", static_cast<audio_channel_mask_t>(AUDIO_CHANNEL_INDEX_MASK_8)},
+};
+template<>
+const size_t ChannelIndexConverter::mSize = sizeof(ChannelIndexConverter::mTable) /
+ sizeof(ChannelIndexConverter::mTable[0]);
+
+
+template <>
+const GainModeConverter::Table GainModeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_JOINT),
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_CHANNELS),
+ MAKE_STRING_FROM_ENUM(AUDIO_GAIN_MODE_RAMP),
+};
+
+template<>
+const size_t GainModeConverter::mSize = sizeof(GainModeConverter::mTable) /
+ sizeof(GainModeConverter::mTable[0]);
+
+template <>
+const DeviceCategoryConverter::Table DeviceCategoryConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_HEADSET),
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_SPEAKER),
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EARPIECE),
+ MAKE_STRING_FROM_ENUM(DEVICE_CATEGORY_EXT_MEDIA)
+};
+
+template<>
+const size_t DeviceCategoryConverter::mSize = sizeof(DeviceCategoryConverter::mTable) /
+ sizeof(DeviceCategoryConverter::mTable[0]);
+
+template <>
+const StreamTypeConverter::Table StreamTypeConverter::mTable[] = {
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_VOICE_CALL),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_SYSTEM),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_RING),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_MUSIC),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ALARM),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_NOTIFICATION),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_BLUETOOTH_SCO ),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ENFORCED_AUDIBLE),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_DTMF),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_TTS),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_ACCESSIBILITY),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_REROUTING),
+ MAKE_STRING_FROM_ENUM(AUDIO_STREAM_PATCH)
+};
+
+template<>
+const size_t StreamTypeConverter::mSize = sizeof(StreamTypeConverter::mTable) /
+ sizeof(StreamTypeConverter::mTable[0]);
+
+template <class Traits>
+bool TypeConverter<Traits>::toString(const typename Traits::Type &value, std::string &str)
+{
+ for (size_t i = 0; i < mSize; i++) {
+ if (mTable[i].value == value) {
+ str = mTable[i].literal;
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class Traits>
+bool TypeConverter<Traits>::fromString(const std::string &str, typename Traits::Type &result)
+{
+ for (size_t i = 0; i < mSize; i++) {
+ if (strcmp(mTable[i].literal, str.c_str()) == 0) {
+ ALOGV("stringToEnum() found %s", mTable[i].literal);
+ result = mTable[i].value;
+ return true;
+ }
+ }
+ return false;
+}
+
+template <class Traits>
+void TypeConverter<Traits>::collectionFromString(const std::string &str,
+ typename Traits::Collection &collection,
+ const char *del)
+{
+ char *literal = strdup(str.c_str());
+
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type value;
+ if (fromString(cstr, value)) {
+ collection.add(value);
+ }
+ }
+ free(literal);
+}
+
+template <class Traits>
+uint32_t TypeConverter<Traits>::maskFromString(const std::string &str, const char *del)
+{
+ char *literal = strdup(str.c_str());
+ uint32_t value = 0;
+ for (const char *cstr = strtok(literal, del); cstr != NULL; cstr = strtok(NULL, del)) {
+ typename Traits::Type type;
+ if (fromString(cstr, type)) {
+ value |= static_cast<uint32_t>(type);
+ }
+ }
+ free(literal);
+ return value;
+}
+
+template class TypeConverter<DeviceTraits>;
+template class TypeConverter<OutputFlagTraits>;
+template class TypeConverter<InputFlagTraits>;
+template class TypeConverter<FormatTraits>;
+template class TypeConverter<OutputChannelTraits>;
+template class TypeConverter<InputChannelTraits>;
+template class TypeConverter<ChannelIndexTraits>;
+template class TypeConverter<GainModeTraits>;
+template class TypeConverter<StreamTraits>;
+template class TypeConverter<DeviceCategoryTraits>;
+
+}; // namespace android
+
diff --git a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
index e73e543..3a3bdbf 100755
--- a/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
+++ b/services/audiopolicy/engine/interface/AudioPolicyManagerInterface.h
@@ -143,7 +143,7 @@
*
* @return amplification value in dB matching the UI index for this given device and stream.
*/
- virtual float volIndexToDb(Volume::device_category deviceCategory, audio_stream_type_t stream,
+ virtual float volIndexToDb(device_category deviceCategory, audio_stream_type_t stream,
int indexInUi) = 0;
/**
diff --git a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
index 74daba5..43d441e 100755
--- a/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
+++ b/services/audiopolicy/engineconfigurable/interface/AudioPolicyPluginInterface.h
@@ -116,7 +116,7 @@
* @return true if the strategy were set correclty for this stream, false otherwise.
*/
virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- Volume::device_category category,
+ device_category category,
const VolumeCurvePoints &points) = 0;
/**
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk b/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
index e9b1902..55da35e 100644
--- a/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/example/Android.mk
@@ -7,6 +7,7 @@
#
################################################################################################
+ifeq (1, 0)
LOCAL_PATH := $(call my-dir)
@@ -103,3 +104,5 @@
LOCAL_SRC_FILES := Settings/$(LOCAL_MODULE_STEM)
include $(BUILD_PREBUILT)
endif # pfw_rebuild_settings
+
+endif # ifeq (1, 0)
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
index 497d555..ccb10ae 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.cpp
@@ -30,24 +30,16 @@
context),
mPolicySubsystem(static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
- mApplicableInputDevice(mDefaultApplicableInputDevice)
+ mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
mId = static_cast<audio_source_t>(context.getItemAsInteger(MappingKeyIdentifier));
// Declares the strategy to audio policy engine
mPolicyPluginInterface->addInputSource(getFormattedMappingValue(), mId);
}
-bool InputSource::receiveFromHW(string & /*error*/)
-{
- blackboardWrite(&mApplicableInputDevice, sizeof(mApplicableInputDevice));
- return true;
-}
-
bool InputSource::sendToHW(string & /*error*/)
{
uint32_t applicableInputDevice;
blackboardRead(&applicableInputDevice, sizeof(applicableInputDevice));
- mApplicableInputDevice = applicableInputDevice;
- return mPolicyPluginInterface->setDeviceForInputSource(mId, mApplicableInputDevice);
+ return mPolicyPluginInterface->setDeviceForInputSource(mId, applicableInputDevice);
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
index 67c5b50..0db4f70 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/InputSource.h
@@ -32,7 +32,6 @@
const CMappingContext &context);
protected:
- virtual bool receiveFromHW(std::string &error);
virtual bool sendToHW(std::string &error);
private:
@@ -44,6 +43,4 @@
android::AudioPolicyPluginInterface *mPolicyPluginInterface;
audio_source_t mId; /**< input source identifier to link with audio.h. */
- uint32_t mApplicableInputDevice; /**< applicable input device for this strategy. */
- static const uint32_t mDefaultApplicableInputDevice = 0; /**< default input device. */
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
index 1848813..5c536d5 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.cpp
@@ -31,8 +31,7 @@
context),
mPolicySubsystem(static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
- mApplicableOutputDevice(mDefaultApplicableOutputDevice)
+ mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
mId = static_cast<routing_strategy>(context.getItemAsInteger(MappingKeyIdentifier));
@@ -40,12 +39,6 @@
mPolicyPluginInterface->addStrategy(getFormattedMappingValue(), mId);
}
-bool Strategy::receiveFromHW(string & /*error*/)
-{
- blackboardWrite(&mApplicableOutputDevice, sizeof(mApplicableOutputDevice));
- return true;
-}
-
bool Strategy::sendToHW(string & /*error*/)
{
uint32_t applicableOutputDevice;
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
index 9a9b3e4..cbb72e2 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Strategy.h
@@ -32,7 +32,6 @@
const CMappingContext &context);
protected:
- virtual bool receiveFromHW(std::string &error);
virtual bool sendToHW(std::string &error);
private:
@@ -44,6 +43,4 @@
android::AudioPolicyPluginInterface *mPolicyPluginInterface;
android::routing_strategy mId; /**< strategy identifier to link with audio.h.*/
- uint32_t mApplicableOutputDevice; /**< applicable output device for this strategy. */
- static const uint32_t mDefaultApplicableOutputDevice = 0; /**< default output device. */
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
index 1916b9b..eb7d78f 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.cpp
@@ -31,8 +31,7 @@
context),
mPolicySubsystem(static_cast<const PolicySubsystem *>(
instanceConfigurableElement->getBelongingSubsystem())),
- mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface()),
- mApplicableStrategy(mDefaultApplicableStrategy)
+ mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
mId = static_cast<audio_usage_t>(context.getItemAsInteger(MappingKeyIdentifier));
@@ -40,17 +39,10 @@
mPolicyPluginInterface->addUsage(getFormattedMappingValue(), mId);
}
-bool Usage::receiveFromHW(string & /*error*/)
-{
- blackboardWrite(&mApplicableStrategy, sizeof(mApplicableStrategy));
- return true;
-}
-
bool Usage::sendToHW(string & /*error*/)
{
uint32_t applicableStrategy;
blackboardRead(&applicableStrategy, sizeof(applicableStrategy));
- mApplicableStrategy = applicableStrategy;
return mPolicyPluginInterface->setStrategyForUsage(mId,
- static_cast<routing_strategy>(mApplicableStrategy));
+ static_cast<routing_strategy>(applicableStrategy));
}
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
index 8e9b638..3b82f8c 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/Usage.h
@@ -32,7 +32,6 @@
const CMappingContext &context);
protected:
- virtual bool receiveFromHW(std::string &error);
virtual bool sendToHW(std::string &error);
private:
@@ -44,6 +43,4 @@
android::AudioPolicyPluginInterface *mPolicyPluginInterface;
audio_usage_t mId; /**< usage identifier to link with audio.h. */
- uint32_t mApplicableStrategy; /**< applicable strategy for this usage. */
- static const uint32_t mDefaultApplicableStrategy = 0; /**< default strategy. */
};
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
index 5c155c8..1469c3f 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.cpp
@@ -36,10 +36,10 @@
mPolicyPluginInterface(mPolicySubsystem->getPolicyPluginInterface())
{
uint32_t categoryKey = context.getItemAsInteger(MappingKeyCategory);
- if (categoryKey >= Volume::DEVICE_CATEGORY_CNT) {
- mCategory = Volume::DEVICE_CATEGORY_SPEAKER;
+ if (categoryKey >= DEVICE_CATEGORY_CNT) {
+ mCategory = DEVICE_CATEGORY_SPEAKER;
} else {
- mCategory = static_cast<Volume::device_category>(categoryKey);
+ mCategory = static_cast<device_category>(categoryKey);
}
mId = static_cast<audio_stream_type_t>(context.getItemAsInteger(MappingKeyIdentifier));
diff --git a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h
index a00ae84..3c2d9bc 100755
--- a/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h
+++ b/services/audiopolicy/engineconfigurable/parameter-framework/plugin/VolumeProfile.h
@@ -58,7 +58,7 @@
audio_stream_type_t mId;
size_t mPoints;
- Volume::device_category mCategory;
+ device_category mCategory;
static const uint32_t gFractional = 8; /**< Beware to align with the structure. */
};
diff --git a/services/audiopolicy/engineconfigurable/src/Collection.h b/services/audiopolicy/engineconfigurable/src/Collection.h
index 8f17b15..b72ded8 100755
--- a/services/audiopolicy/engineconfigurable/src/Collection.h
+++ b/services/audiopolicy/engineconfigurable/src/Collection.h
@@ -47,6 +47,7 @@
class Collection : public std::map<Key, Element<Key> *>
{
private:
+ typedef std::map<Key, Element<Key> *> Base;
typedef Element<Key> T;
typedef typename std::map<Key, T *>::iterator CollectionIterator;
typedef typename std::map<Key, T *>::const_iterator CollectionConstIterator;
@@ -127,7 +128,7 @@
for (it = (*this).begin(); it != (*this).end(); ++it) {
delete it->second;
}
- (*this).clear();
+ Base::clear();
}
private:
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.cpp b/services/audiopolicy/engineconfigurable/src/Engine.cpp
index 733cdf6..074af50 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Engine.cpp
@@ -116,7 +116,7 @@
}
bool Engine::setVolumeProfileForStream(const audio_stream_type_t &streamType,
- Volume::device_category deviceCategory,
+ device_category deviceCategory,
const VolumeCurvePoints &points)
{
Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
@@ -199,9 +199,9 @@
return element->template set<Property>(property) == NO_ERROR;
}
-float Engine::volIndexToDb(Volume::device_category category,
- audio_stream_type_t streamType,
- int indexInUi)
+float Engine::volIndexToDb(device_category category,
+ audio_stream_type_t streamType,
+ int indexInUi)
{
Stream *stream = getFromCollection<audio_stream_type_t>(streamType);
if (stream == NULL) {
@@ -246,10 +246,17 @@
return mPolicyParameterMgr->getForceUse(usage);
}
-status_t Engine::setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
- const char *deviceAddress)
+status_t Engine::setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t /*state*/)
{
- return mPolicyParameterMgr->setDeviceConnectionState(devices, state, deviceAddress);
+ if (audio_is_output_device(devDesc->type())) {
+ return mPolicyParameterMgr->setAvailableOutputDevices(
+ mApmObserver->getAvailableOutputDevices().types());
+ } else if (audio_is_input_device(devDesc->type())) {
+ return mPolicyParameterMgr->setAvailableInputDevices(
+ mApmObserver->getAvailableInputDevices().types());
+ }
+ return BAD_TYPE;
}
template <>
diff --git a/services/audiopolicy/engineconfigurable/src/Engine.h b/services/audiopolicy/engineconfigurable/src/Engine.h
index 6fa7a13..8a15e5e 100755
--- a/services/audiopolicy/engineconfigurable/src/Engine.h
+++ b/services/audiopolicy/engineconfigurable/src/Engine.h
@@ -86,8 +86,7 @@
virtual android::status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
audio_policy_dev_state_t state)
{
- return mPolicyEngine->setDeviceConnectionState(devDesc->type(), state,
- devDesc->mAddress);
+ return mPolicyEngine->setDeviceConnectionState(devDesc, state);
}
virtual status_t initStreamVolume(audio_stream_type_t stream,
int indexMin, int indexMax)
@@ -97,9 +96,9 @@
virtual void initializeVolumeCurves(bool /*isSpeakerDrcEnabled*/) {}
- virtual float volIndexToDb(Volume::device_category deviceCategory,
- audio_stream_type_t stream,
- int indexInUi)
+ virtual float volIndexToDb(device_category deviceCategory,
+ audio_stream_type_t stream,
+ int indexInUi)
{
return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
}
@@ -142,7 +141,7 @@
stream);
}
virtual bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- Volume::device_category deviceCategory,
+ device_category deviceCategory,
const VolumeCurvePoints &points)
{
return mPolicyEngine->setVolumeProfileForStream(stream, deviceCategory, points);
@@ -172,7 +171,7 @@
void setObserver(AudioPolicyManagerObserver *observer);
bool setVolumeProfileForStream(const audio_stream_type_t &stream,
- Volume::device_category deviceCategory,
+ device_category deviceCategory,
const VolumeCurvePoints &points);
status_t initCheck();
@@ -180,12 +179,9 @@
audio_mode_t getPhoneState() const;
status_t setForceUse(audio_policy_force_use_t usage, audio_policy_forced_cfg_t config);
audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
- status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
- const char *deviceAddress);
-
- float volIndexToDb(Volume::device_category category,
- audio_stream_type_t stream,
- int indexInUi);
+ status_t setDeviceConnectionState(const sp<DeviceDescriptor> devDesc,
+ audio_policy_dev_state_t state);
+ float volIndexToDb(device_category category, audio_stream_type_t stream, int indexInUi);
status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
StrategyCollection mStrategyCollection; /**< Strategies indexed by their enum id. */
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.cpp b/services/audiopolicy/engineconfigurable/src/Stream.cpp
index a929435..3bd5220 100755
--- a/services/audiopolicy/engineconfigurable/src/Stream.cpp
+++ b/services/audiopolicy/engineconfigurable/src/Stream.cpp
@@ -62,15 +62,15 @@
return mApplicableStrategy;
}
-status_t Element<audio_stream_type_t>::setVolumeProfile(Volume::device_category category,
+status_t Element<audio_stream_type_t>::setVolumeProfile(device_category category,
const VolumeCurvePoints &points)
{
- ALOGD("%s: adding volume profile for %s for device category %d, points nb =%d", __FUNCTION__,
+ ALOGD("%s: adding volume profile for %s for device category %d, points nb =%zu", __FUNCTION__,
getName().c_str(), category, points.size());
mVolumeProfiles[category] = points;
for (size_t i = 0; i < points.size(); i++) {
- ALOGV("%s: %s cat=%d curve index =%d Index=%d dBAttenuation=%f",
+ ALOGV("%s: %s cat=%d curve index =%zu Index=%d dBAttenuation=%f",
__FUNCTION__, getName().c_str(), category, i, points[i].mIndex,
points[i].mDBAttenuation);
}
@@ -91,8 +91,7 @@
return NO_ERROR;
}
-float Element<audio_stream_type_t>::volIndexToDb(Volume::device_category deviceCategory,
- int indexInUi)
+float Element<audio_stream_type_t>::volIndexToDb(device_category deviceCategory, int indexInUi)
{
VolumeProfileConstIterator it = mVolumeProfiles.find(deviceCategory);
if (it == mVolumeProfiles.end()) {
diff --git a/services/audiopolicy/engineconfigurable/src/Stream.h b/services/audiopolicy/engineconfigurable/src/Stream.h
index 8c39dc6..b103f89 100755
--- a/services/audiopolicy/engineconfigurable/src/Stream.h
+++ b/services/audiopolicy/engineconfigurable/src/Stream.h
@@ -33,7 +33,7 @@
class Element<audio_stream_type_t>
{
private:
- typedef std::map<Volume::device_category, VolumeCurvePoints> VolumeProfiles;
+ typedef std::map<device_category, VolumeCurvePoints> VolumeProfiles;
typedef VolumeProfiles::iterator VolumeProfileIterator;
typedef VolumeProfiles::const_iterator VolumeProfileConstIterator;
@@ -79,9 +79,9 @@
template <typename Property>
status_t set(Property property);
- status_t setVolumeProfile(Volume::device_category category, const VolumeCurvePoints &points);
+ status_t setVolumeProfile(device_category category, const VolumeCurvePoints &points);
- float volIndexToDb(Volume::device_category deviceCategory, int indexInUi);
+ float volIndexToDb(device_category deviceCategory, int indexInUi);
status_t initVolume(int indexMin, int indexMax);
diff --git a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
index cfe49d4..3e40a2b 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
+++ b/services/audiopolicy/engineconfigurable/wrapper/ParameterManagerWrapper.cpp
@@ -387,41 +387,26 @@
return interface->getLiteralValue(valueToCheck, literalValue);
}
-status_t ParameterManagerWrapper::setDeviceConnectionState(audio_devices_t devices,
- audio_policy_dev_state_t state,
- const char */*deviceAddres*/)
+status_t ParameterManagerWrapper::setAvailableInputDevices(audio_devices_t inputDevices)
{
- ISelectionCriterionInterface *criterion = NULL;
-
- if (audio_is_output_devices(devices)) {
- criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
- } else if (devices & AUDIO_DEVICE_BIT_IN) {
- criterion = mPolicyCriteria[gInputDeviceCriterionTag];
- } else {
- return BAD_TYPE;
- }
+ ISelectionCriterionInterface *criterion = mPolicyCriteria[gInputDeviceCriterionTag];
if (criterion == NULL) {
- ALOGE("%s: no criterion found for devices", __FUNCTION__);
+ ALOGE("%s: no criterion found for input devices", __FUNCTION__);
return DEAD_OBJECT;
}
+ criterion->setCriterionState(inputDevices & ~AUDIO_DEVICE_BIT_IN);
+ applyPlatformConfiguration();
+ return NO_ERROR;
+}
- int32_t previousDevices = criterion->getCriterionState();
- switch (state)
- {
- case AUDIO_POLICY_DEVICE_STATE_AVAILABLE:
- criterion->setCriterionState(previousDevices |= devices);
- break;
-
- case AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE:
- if (devices & AUDIO_DEVICE_BIT_IN) {
- devices &= ~AUDIO_DEVICE_BIT_IN;
- }
- criterion->setCriterionState(previousDevices &= ~devices);
- break;
-
- default:
- return BAD_VALUE;
+status_t ParameterManagerWrapper::setAvailableOutputDevices(audio_devices_t outputDevices)
+{
+ ISelectionCriterionInterface *criterion = mPolicyCriteria[gOutputDeviceCriterionTag];
+ if (criterion == NULL) {
+ ALOGE("%s: no criterion found for output devices", __FUNCTION__);
+ return DEAD_OBJECT;
}
+ criterion->setCriterionState(outputDevices);
applyPlatformConfiguration();
return NO_ERROR;
}
diff --git a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
index 3c5f2c0..4c1acfe 100755
--- a/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
+++ b/services/audiopolicy/engineconfigurable/wrapper/include/ParameterManagerWrapper.h
@@ -103,18 +103,22 @@
audio_policy_forced_cfg_t getForceUse(audio_policy_force_use_t usage) const;
/**
- * Set the connection state of device(s).
- * It will set the associated policy parameter framework criterion.
+ * Set the available input devices i.e. set the associated policy parameter framework criterion
*
- * @param[in] devices mask of devices for which the state has changed.
- * @param[in] state of availability of this(these) device(s).
- * @param[in] deviceAddress: the mask might not be enough, as it may represents a type of
- * device, so address of the device will help precise identification.
+ * @param[in] inputDevices mask of available input devices.
*
* @return NO_ERROR if devices criterion updated correctly, error code otherwise.
*/
- status_t setDeviceConnectionState(audio_devices_t devices, audio_policy_dev_state_t state,
- const char *deviceAddress);
+ status_t setAvailableInputDevices(audio_devices_t inputDevices);
+
+ /**
+ * Set the available output devices i.e. set the associated policy parameter framework criterion
+ *
+ * @param[in] outputDevices mask of available output devices.
+ *
+ * @return NO_ERROR if devices criterion updated correctly, error code otherwise.
+ */
+ status_t setAvailableOutputDevices(audio_devices_t outputDevices);
private:
/**
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 0686414..b0df018 100755
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -63,8 +63,7 @@
return (mApmObserver != NULL) ? NO_ERROR : NO_INIT;
}
-float Engine::volIndexToDb(Volume::device_category category, audio_stream_type_t streamType,
- int indexInUi)
+float Engine::volIndexToDb(device_category category, audio_stream_type_t streamType, int indexInUi)
{
const StreamDescriptor &streamDesc = mApmObserver->getStreamDescriptors().valueAt(streamType);
return Gains::volIndexToDb(category, streamDesc, indexInUi);
@@ -89,26 +88,26 @@
StreamDescriptorCollection &streams = mApmObserver->getStreamDescriptors();
for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
- for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
streams.setVolumeCurvePoint(static_cast<audio_stream_type_t>(i),
- static_cast<Volume::device_category>(j),
+ static_cast<device_category>(j),
Gains::sVolumeProfiles[i][j]);
}
}
// Check availability of DRC on speaker path: if available, override some of the speaker curves
if (isSpeakerDrcEnabled) {
- streams.setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, Volume::DEVICE_CATEGORY_SPEAKER,
+ streams.setVolumeCurvePoint(AUDIO_STREAM_SYSTEM, DEVICE_CATEGORY_SPEAKER,
Gains::sDefaultSystemVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_RING, Volume::DEVICE_CATEGORY_SPEAKER,
+ streams.setVolumeCurvePoint(AUDIO_STREAM_RING, DEVICE_CATEGORY_SPEAKER,
Gains::sSpeakerSonificationVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_ALARM, Volume::DEVICE_CATEGORY_SPEAKER,
+ streams.setVolumeCurvePoint(AUDIO_STREAM_ALARM, DEVICE_CATEGORY_SPEAKER,
Gains::sSpeakerSonificationVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, Volume::DEVICE_CATEGORY_SPEAKER,
+ streams.setVolumeCurvePoint(AUDIO_STREAM_NOTIFICATION, DEVICE_CATEGORY_SPEAKER,
Gains::sSpeakerSonificationVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_MUSIC, Volume::DEVICE_CATEGORY_SPEAKER,
+ streams.setVolumeCurvePoint(AUDIO_STREAM_MUSIC, DEVICE_CATEGORY_SPEAKER,
Gains::sSpeakerMediaVolumeCurveDrc);
- streams.setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, Volume::DEVICE_CATEGORY_SPEAKER,
+ streams.setVolumeCurvePoint(AUDIO_STREAM_ACCESSIBILITY, DEVICE_CATEGORY_SPEAKER,
Gains::sSpeakerMediaVolumeCurveDrc);
}
}
@@ -135,14 +134,14 @@
// are we entering or starting a call
if (!is_state_in_call(oldState) && is_state_in_call(state)) {
ALOGV(" Entering call in setPhoneState()");
- for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
- streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<device_category>(j),
Gains::sVolumeProfiles[AUDIO_STREAM_VOICE_CALL][j]);
}
} else if (is_state_in_call(oldState) && !is_state_in_call(state)) {
ALOGV(" Exiting call in setPhoneState()");
- for (int j = 0; j < Volume::DEVICE_CATEGORY_CNT; j++) {
- streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<Volume::device_category>(j),
+ for (int j = 0; j < DEVICE_CATEGORY_CNT; j++) {
+ streams.setVolumeCurvePoint(AUDIO_STREAM_DTMF, static_cast<device_category>(j),
Gains::sVolumeProfiles[AUDIO_STREAM_DTMF][j]);
}
}
@@ -663,6 +662,7 @@
break;
case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_UNPROCESSED:
case AUDIO_SOURCE_HOTWORD:
if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO &&
availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
diff --git a/services/audiopolicy/enginedefault/src/Engine.h b/services/audiopolicy/enginedefault/src/Engine.h
index 56a4748..697f19b 100755
--- a/services/audiopolicy/enginedefault/src/Engine.h
+++ b/services/audiopolicy/enginedefault/src/Engine.h
@@ -101,8 +101,8 @@
{
return mPolicyEngine->initializeVolumeCurves(isSpeakerDrcEnabled);
}
- virtual float volIndexToDb(Volume::device_category deviceCategory,
- audio_stream_type_t stream,int indexInUi)
+ virtual float volIndexToDb(device_category deviceCategory,
+ audio_stream_type_t stream, int indexInUi)
{
return mPolicyEngine->volIndexToDb(deviceCategory, stream, indexInUi);
}
@@ -141,8 +141,7 @@
audio_devices_t getDeviceForStrategy(routing_strategy strategy) const;
audio_devices_t getDeviceForInputSource(audio_source_t inputSource) const;
- float volIndexToDb(Volume::device_category category,
- audio_stream_type_t stream, int indexInUi);
+ float volIndexToDb(device_category category, audio_stream_type_t stream, int indexInUi);
status_t initStreamVolume(audio_stream_type_t stream, int indexMin, int indexMax);
void initializeVolumeCurves(bool isSpeakerDrcEnabled);
diff --git a/services/audiopolicy/enginedefault/src/Gains.cpp b/services/audiopolicy/enginedefault/src/Gains.cpp
index d06365c..0aace36 100644
--- a/services/audiopolicy/enginedefault/src/Gains.cpp
+++ b/services/audiopolicy/enginedefault/src/Gains.cpp
@@ -114,7 +114,7 @@
};
const VolumeCurvePoint *Gains::sVolumeProfiles[AUDIO_STREAM_CNT]
- [Volume::DEVICE_CATEGORY_CNT] = {
+ [DEVICE_CATEGORY_CNT] = {
{ // AUDIO_STREAM_VOICE_CALL
Gains::sDefaultVoiceVolumeCurve, // DEVICE_CATEGORY_HEADSET
Gains::sSpeakerVoiceVolumeCurve, // DEVICE_CATEGORY_SPEAKER
@@ -197,7 +197,7 @@
};
//static
-float Gains::volIndexToDb(Volume::device_category deviceCategory,
+float Gains::volIndexToDb(device_category deviceCategory,
const StreamDescriptor& streamDesc,
int indexInUi)
{
@@ -243,7 +243,7 @@
//static
-float Gains::volIndexToAmpl(Volume::device_category deviceCategory,
+float Gains::volIndexToAmpl(device_category deviceCategory,
const StreamDescriptor& streamDesc,
int indexInUi)
{
diff --git a/services/audiopolicy/enginedefault/src/Gains.h b/services/audiopolicy/enginedefault/src/Gains.h
index 7620b7d..4bd5edd 100644
--- a/services/audiopolicy/enginedefault/src/Gains.h
+++ b/services/audiopolicy/enginedefault/src/Gains.h
@@ -29,11 +29,11 @@
class Gains
{
public :
- static float volIndexToAmpl(Volume::device_category deviceCategory,
+ static float volIndexToAmpl(device_category deviceCategory,
const StreamDescriptor& streamDesc,
int indexInUi);
- static float volIndexToDb(Volume::device_category deviceCategory,
+ static float volIndexToDb(device_category deviceCategory,
const StreamDescriptor& streamDesc,
int indexInUi);
@@ -58,7 +58,7 @@
static const VolumeCurvePoint sSilentVolumeCurve[Volume::VOLCNT];
static const VolumeCurvePoint sFullScaleVolumeCurve[Volume::VOLCNT];
// default volume curves per stream and device category. See initializeVolumeCurves()
- static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][Volume::DEVICE_CATEGORY_CNT];
+ static const VolumeCurvePoint *sVolumeProfiles[AUDIO_STREAM_CNT][DEVICE_CATEGORY_CNT];
};
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 5ff1c0b..04af88d 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -37,8 +37,8 @@
#include <media/AudioPolicyHelper.h>
#include <soundtrigger/SoundTrigger.h>
#include "AudioPolicyManager.h"
-#include "audio_policy_conf.h"
#include <ConfigParsingUtils.h>
+#include "TypeConverter.h"
#include <policy.h>
namespace android {
@@ -190,6 +190,10 @@
}
}
+ if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+ cleanUpForDevice(devDesc);
+ }
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is output device
@@ -266,6 +270,10 @@
updateCallRouting(newDevice);
}
+ if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) {
+ cleanUpForDevice(devDesc);
+ }
+
mpClientInterface->onAudioPortListUpdate();
return NO_ERROR;
} // end if is input device
@@ -410,7 +418,9 @@
if (activeInput != 0) {
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
if (activeDesc->getModuleHandle() == txSourceDeviceDesc->getModuleHandle()) {
- audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
+ //FIXME: consider all active sessions
+ AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+ audio_session_t activeSession = activeSessions.keyAt(0);
stopInput(activeInput, activeSession);
releaseInput(activeInput, activeSession);
}
@@ -583,7 +593,7 @@
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
audio_devices_t newDevice = getNewInputDevice(activeInput);
// Force new input selection if the new device can not be reached via current input
- if (activeDesc->mProfile->mSupportedDevices.types() & (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
+ if (activeDesc->mProfile->getSupportedDevices().types() & (newDevice & ~AUDIO_DEVICE_BIT_IN)) {
setInputDevice(activeInput, newDevice);
} else {
closeInput(activeInput);
@@ -628,15 +638,15 @@
continue;
}
// reject profiles not corresponding to a device currently available
- if ((mAvailableOutputDevices.types() & curProfile->mSupportedDevices.types()) == 0) {
+ if ((mAvailableOutputDevices.types() & curProfile->getSupportedDevicesType()) == 0) {
continue;
}
// if several profiles are compatible, give priority to one with offload capability
- if (profile != 0 && ((curProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
+ if (profile != 0 && ((curProfile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
continue;
}
profile = curProfile;
- if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
+ if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
break;
}
}
@@ -832,15 +842,15 @@
goto non_direct_output;
}
- // Do not allow offloading if one non offloadable effect is enabled. This prevents from
- // creating an offloaded track and tearing it down immediately after start when audioflinger
- // detects there is an active non offloadable effect.
+ // Do not allow offloading if one non offloadable effect is enabled or MasterMono is enabled.
+ // This prevents creating an offloaded track and tearing it down immediately after start
+ // when audioflinger detects there is an active non offloadable effect.
// FIXME: We should check the audio session here but we do not have it in this context.
// This may prevent offloading in rare situations where effects are left active by apps
// in the background.
if (((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) ||
- !mEffects.isNonOffloadableEffectEnabled()) {
+ !(mEffects.isNonOffloadableEffectEnabled() || mMasterMono)) {
profile = getProfileForDirectOutput(device,
samplingRate,
format,
@@ -873,7 +883,7 @@
// if the selected profile is offloaded and no offload info was specified,
// create a default one
audio_offload_info_t defaultOffloadInfo = AUDIO_INFO_INITIALIZER;
- if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
+ if ((profile->getFlags() & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
defaultOffloadInfo.sample_rate = samplingRate;
defaultOffloadInfo.channel_mask = channelMask;
@@ -1001,13 +1011,13 @@
}
}
- int commonFlags = popcount(outputDesc->mProfile->mFlags & flags);
+ int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
if (commonFlags > maxCommonFlags) {
outputFlags = outputs[i];
maxCommonFlags = commonFlags;
ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
}
- if (outputDesc->mProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
outputPrimary = outputs[i];
}
}
@@ -1321,7 +1331,6 @@
audio_devices_t device;
// handle legacy remote submix case where the address was not always specified
String8 address = String8("");
- bool isSoundTrigger = false;
audio_source_t inputSource = attr->source;
audio_source_t halInputSource;
AudioMix *policyMix = NULL;
@@ -1376,30 +1385,45 @@
} else {
*inputType = API_INPUT_LEGACY;
}
- // adapt channel selection to input source
- switch (inputSource) {
- case AUDIO_SOURCE_VOICE_UPLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK;
- break;
- case AUDIO_SOURCE_VOICE_DOWNLINK:
- channelMask = AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- case AUDIO_SOURCE_VOICE_CALL:
- channelMask = AUDIO_CHANNEL_IN_VOICE_UPLINK | AUDIO_CHANNEL_IN_VOICE_DNLINK;
- break;
- default:
- break;
- }
- if (inputSource == AUDIO_SOURCE_HOTWORD) {
- ssize_t index = mSoundTriggerSessions.indexOfKey(session);
- if (index >= 0) {
- *input = mSoundTriggerSessions.valueFor(session);
- isSoundTrigger = true;
- flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
- ALOGV("SoundTrigger capture on session %d input %d", session, *input);
- } else {
- halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
- }
+
+ }
+
+ *input = getInputForDevice(device, address, session, uid, inputSource,
+ samplingRate, format, channelMask, flags,
+ policyMix);
+ if (*input == AUDIO_IO_HANDLE_NONE) {
+ mInputRoutes.removeRoute(session);
+ return INVALID_OPERATION;
+ }
+ ALOGV("getInputForAttr() returns input type = %d", *inputType);
+ return NO_ERROR;
+}
+
+
+audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
+ String8 address,
+ audio_session_t session,
+ uid_t uid,
+ audio_source_t inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ AudioMix *policyMix)
+{
+ audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
+ audio_source_t halInputSource = inputSource;
+ bool isSoundTrigger = false;
+
+ if (inputSource == AUDIO_SOURCE_HOTWORD) {
+ ssize_t index = mSoundTriggerSessions.indexOfKey(session);
+ if (index >= 0) {
+ input = mSoundTriggerSessions.valueFor(session);
+ isSoundTrigger = true;
+ flags = (audio_input_flags_t)(flags | AUDIO_INPUT_FLAG_HW_HOTWORD);
+ ALOGV("SoundTrigger capture on session %d input %d", session, input);
+ } else {
+ halInputSource = AUDIO_SOURCE_VOICE_RECOGNITION;
}
}
@@ -1419,25 +1443,63 @@
} else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
} else { // fail
- ALOGW("getInputForAttr() could not find profile for device 0x%X, samplingRate %u,"
- "format %#x, channelMask 0x%X, flags %#x",
+ ALOGW("getInputForDevice() could not find profile for device 0x%X,"
+ "samplingRate %u, format %#x, channelMask 0x%X, flags %#x",
device, samplingRate, format, channelMask, flags);
- return BAD_VALUE;
+ return input;
}
}
if (profile->getModuleHandle() == 0) {
ALOGE("getInputForAttr(): HW module %s not opened", profile->getModuleName());
- return NO_INIT;
+ return input;
}
+ sp<AudioSession> audioSession = new AudioSession(session,
+ inputSource,
+ format,
+ samplingRate,
+ channelMask,
+ flags,
+ uid,
+ isSoundTrigger,
+ policyMix, mpClientInterface);
+
+// TODO enable input reuse
+#if 0
+ // reuse an open input if possible
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ sp<AudioInputDescriptor> desc = mInputs.valueAt(i);
+ // reuse input if it shares the same profile and same sound trigger attribute
+ if (profile == desc->mProfile &&
+ isSoundTrigger == desc->isSoundTrigger()) {
+
+ sp<AudioSession> as = desc->getAudioSession(session);
+ if (as != 0) {
+ // do not allow unmatching properties on same session
+ if (as->matches(audioSession)) {
+ as->changeOpenCount(1);
+ } else {
+ ALOGW("getInputForDevice() record with different attributes"
+ " exists for session %d", session);
+ return input;
+ }
+ } else {
+ desc->addAudioSession(session, audioSession);
+ }
+ ALOGV("getInputForDevice() reusing input %d", mInputs.keyAt(i));
+ return mInputs.keyAt(i);
+ }
+ }
+#endif
+
audio_config_t config = AUDIO_CONFIG_INITIALIZER;
config.sample_rate = profileSamplingRate;
config.channel_mask = profileChannelMask;
config.format = profileFormat;
status_t status = mpClientInterface->openInput(profile->getModuleHandle(),
- input,
+ &input,
&config,
&device,
address,
@@ -1445,37 +1507,31 @@
profileFlags);
// only accept input with the exact requested set of parameters
- if (status != NO_ERROR || *input == AUDIO_IO_HANDLE_NONE ||
+ if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE ||
(profileSamplingRate != config.sample_rate) ||
(profileFormat != config.format) ||
(profileChannelMask != config.channel_mask)) {
- ALOGW("getInputForAttr() failed opening input: samplingRate %d, format %d,"
- " channelMask %x",
+ ALOGW("getInputForAttr() failed opening input: samplingRate %d"
+ ", format %d, channelMask %x",
samplingRate, format, channelMask);
- if (*input != AUDIO_IO_HANDLE_NONE) {
- mpClientInterface->closeInput(*input);
+ if (input != AUDIO_IO_HANDLE_NONE) {
+ mpClientInterface->closeInput(input);
}
- return BAD_VALUE;
+ return AUDIO_IO_HANDLE_NONE;
}
sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(profile);
- inputDesc->mInputSource = inputSource;
- inputDesc->mRefCount = 0;
- inputDesc->mOpenRefCount = 1;
inputDesc->mSamplingRate = profileSamplingRate;
inputDesc->mFormat = profileFormat;
inputDesc->mChannelMask = profileChannelMask;
inputDesc->mDevice = device;
- inputDesc->mSessions.add(session);
- inputDesc->mIsSoundTrigger = isSoundTrigger;
inputDesc->mPolicyMix = policyMix;
+ inputDesc->addAudioSession(session, audioSession);
- ALOGV("getInputForAttr() returns input type = %d", *inputType);
-
- addInput(*input, inputDesc);
+ addInput(input, inputDesc);
mpClientInterface->onAudioPortListUpdate();
- return NO_ERROR;
+ return input;
}
status_t AudioPolicyManager::startInput(audio_io_handle_t input,
@@ -1489,8 +1545,8 @@
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- index = inputDesc->mSessions.indexOf(session);
- if (index < 0) {
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+ if (audioSession == 0) {
ALOGW("startInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
}
@@ -1505,11 +1561,14 @@
// If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
// otherwise the active input continues and the new input cannot be started.
sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
- if ((activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) &&
+ if ((activeDesc->inputSource() == AUDIO_SOURCE_HOTWORD) &&
!activeDesc->hasPreemptedSession(session)) {
ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
- audio_session_t activeSession = activeDesc->mSessions.itemAt(0);
- SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
+ //FIXME: consider all active sessions
+ AudioSessionCollection activeSessions = activeDesc->getActiveAudioSessions();
+ audio_session_t activeSession = activeSessions.keyAt(0);
+ SortedVector<audio_session_t> sessions =
+ activeDesc->getPreemptedSessions();
sessions.add(activeSession);
inputDesc->setPreemptedSessions(sessions);
stopInput(activeInput, activeSession);
@@ -1533,7 +1592,7 @@
// Routing?
mInputRoutes.incRouteActivity(session);
- if (inputDesc->mRefCount == 0 || mInputRoutes.hasRouteChanged(session)) {
+ if (!inputDesc->isActive() || mInputRoutes.hasRouteChanged(session)) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
@@ -1564,9 +1623,9 @@
}
}
- ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
+ ALOGV("AudioPolicyManager::startInput() input source = %d", audioSession->inputSource());
- inputDesc->mRefCount++;
+ audioSession->changeActiveCount(1);
return NO_ERROR;
}
@@ -1581,23 +1640,23 @@
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- index = inputDesc->mSessions.indexOf(session);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (index < 0) {
ALOGW("stopInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
}
- if (inputDesc->mRefCount == 0) {
+ if (audioSession->activeCount() == 0) {
ALOGW("stopInput() input %d already stopped", input);
return INVALID_OPERATION;
}
- inputDesc->mRefCount--;
+ audioSession->changeActiveCount(-1);
// Routing?
mInputRoutes.decRouteActivity(session);
- if (inputDesc->mRefCount == 0) {
+ if (!inputDesc->isActive()) {
// if input maps to a dynamic policy with an activity listener, notify of state change
if ((inputDesc->mPolicyMix != NULL)
&& ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) {
@@ -1634,6 +1693,7 @@
void AudioPolicyManager::releaseInput(audio_io_handle_t input,
audio_session_t session)
{
+
ALOGV("releaseInput() %d", input);
ssize_t index = mInputs.indexOfKey(input);
if (index < 0) {
@@ -1647,18 +1707,23 @@
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
ALOG_ASSERT(inputDesc != 0);
- index = inputDesc->mSessions.indexOf(session);
+ sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (index < 0) {
ALOGW("releaseInput() unknown session %d on input %d", session, input);
return;
}
- inputDesc->mSessions.remove(session);
- if (inputDesc->mOpenRefCount == 0) {
- ALOGW("releaseInput() invalid open ref count %d", inputDesc->mOpenRefCount);
+
+ if (audioSession->openCount() == 0) {
+ ALOGW("releaseInput() invalid open count %d on session %d",
+ audioSession->openCount(), session);
return;
}
- inputDesc->mOpenRefCount--;
- if (inputDesc->mOpenRefCount > 0) {
+
+ if (audioSession->changeOpenCount(-1) == 0) {
+ inputDesc->removeAudioSession(session);
+ }
+
+ if (inputDesc->getOpenRefCount() > 0) {
ALOGV("releaseInput() exit > 0");
return;
}
@@ -1872,23 +1937,9 @@
{
for (size_t i = 0; i < mInputs.size(); i++) {
const sp<AudioInputDescriptor> inputDescriptor = mInputs.valueAt(i);
- if (inputDescriptor->mRefCount == 0) {
- continue;
- }
- if (inputDescriptor->mInputSource == (int)source) {
+ if (inputDescriptor->isSourceActive(source)) {
return true;
}
- // AUDIO_SOURCE_HOTWORD is equivalent to AUDIO_SOURCE_VOICE_RECOGNITION only if it
- // corresponds to an active capture triggered by a hardware hotword recognition
- if ((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
- (inputDescriptor->mInputSource == AUDIO_SOURCE_HOTWORD)) {
- // FIXME: we should not assume that the first session is the active one and keep
- // activity count per session. Same in startInput().
- ssize_t index = mSoundTriggerSessions.indexOfKey(inputDescriptor->mSessions.itemAt(0));
- if (index >= 0) {
- return true;
- }
- }
}
return false;
}
@@ -1931,7 +1982,7 @@
return INVALID_OPERATION;
}
- ALOGV("registerPolicyMixes() num mixes %d", mixes.size());
+ ALOGV("registerPolicyMixes() num mixes %zu", mixes.size());
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
@@ -1978,7 +2029,7 @@
return INVALID_OPERATION;
}
- ALOGV("unregisterPolicyMixes() num mixes %d", mixes.size());
+ ALOGV("unregisterPolicyMixes() num mixes %zu", mixes.size());
for (size_t i = 0; i < mixes.size(); i++) {
String8 address = mixes[i].mRegistrationId;
@@ -2039,11 +2090,13 @@
result.append(buffer);
snprintf(buffer, SIZE, " TTS output %s\n", mTtsOutputAvailable ? "available" : "not available");
result.append(buffer);
+ snprintf(buffer, SIZE, " Master mono: %s\n", mMasterMono ? "on" : "off");
+ result.append(buffer);
write(fd, result.string(), result.size());
- mAvailableOutputDevices.dump(fd, String8("output"));
- mAvailableInputDevices.dump(fd, String8("input"));
+ mAvailableOutputDevices.dump(fd, String8("Available output"));
+ mAvailableInputDevices.dump(fd, String8("Available input"));
mHwModules.dump(fd);
mOutputs.dump(fd);
mInputs.dump(fd);
@@ -2066,6 +2119,10 @@
offloadInfo.stream_type, offloadInfo.bit_rate, offloadInfo.duration_us,
offloadInfo.has_video);
+ if (mMasterMono) {
+ return false; // no offloading if mono is set.
+ }
+
// Check if offload has been disabled
char propValue[PROPERTY_VALUE_MAX];
if (property_get("audio.offload.disable", propValue, "0")) {
@@ -2223,7 +2280,7 @@
patch->sources[0].type);
#if LOG_NDEBUG == 0
for (size_t i = 0; i < patch->num_sinks; i++) {
- ALOGV("createAudioPatch sink %d: id %d role %d type %d", i, patch->sinks[i].id,
+ ALOGV("createAudioPatch sink %zu: id %d role %d type %d", i, patch->sinks[i].id,
patch->sinks[i].role,
patch->sinks[i].type);
}
@@ -2392,7 +2449,7 @@
// - source and sink devices are on differnt HW modules OR
// - audio HAL version is < 3.0
if ((srcDeviceDesc->getModuleHandle() != sinkDeviceDesc->getModuleHandle()) ||
- (srcDeviceDesc->mModule->mHalVersion < AUDIO_DEVICE_API_VERSION_3_0)) {
+ (srcDeviceDesc->mModule->getHalVersion() < AUDIO_DEVICE_API_VERSION_3_0)) {
// support only one sink device for now to simplify output selection logic
if (patch->num_sinks > 1) {
return INVALID_OPERATION;
@@ -2588,6 +2645,7 @@
void AudioPolicyManager::releaseResourcesForUid(uid_t uid)
{
+ clearAudioSources(uid);
clearAudioPatches(uid);
clearSessionRoutes(uid);
}
@@ -2602,7 +2660,6 @@
}
}
-
void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy,
audio_io_handle_t ouptutToSkip)
{
@@ -2668,7 +2725,7 @@
SortedVector<audio_io_handle_t> inputsToClose;
for (size_t i = 0; i < mInputs.size(); i++) {
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- if (affectedSources.indexOf(inputDesc->mInputSource) >= 0) {
+ if (affectedSources.indexOf(inputDesc->inputSource()) >= 0) {
inputsToClose.add(inputDesc->mIoHandle);
}
}
@@ -2677,6 +2734,15 @@
}
}
+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) {
+ stopAudioSource(mAudioSources.keyAt(i));
+ }
+ }
+}
status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
@@ -2689,16 +2755,219 @@
return mSoundTriggerSessions.acquireSession(*session, *ioHandle);
}
-status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source __unused,
- const audio_attributes_t *attributes __unused,
- audio_io_handle_t *handle __unused)
+status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
+ const audio_attributes_t *attributes,
+ audio_io_handle_t *handle,
+ uid_t uid)
{
- return INVALID_OPERATION;
+ ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
+ if (source == NULL || attributes == NULL || handle == NULL) {
+ return BAD_VALUE;
+ }
+
+ *handle = AUDIO_IO_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);
+ return INVALID_OPERATION;
+ }
+
+ sp<DeviceDescriptor> srcDeviceDesc =
+ 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);
+ return BAD_VALUE;
+ }
+ sp<AudioSourceDescriptor> sourceDesc =
+ new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
+
+ struct audio_patch dummyPatch;
+ sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
+ sourceDesc->mPatchDesc = patchDesc;
+
+ status_t status = connectAudioSource(sourceDesc);
+ if (status == NO_ERROR) {
+ mAudioSources.add(sourceDesc->getHandle(), sourceDesc);
+ *handle = sourceDesc->getHandle();
+ }
+ return status;
+}
+
+status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+ // make sure we only have one patch per source.
+ disconnectAudioSource(sourceDesc);
+
+ routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+ audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+ sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
+
+ audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
+ sp<DeviceDescriptor> sinkDeviceDesc =
+ mAvailableOutputDevices.getDevice(sinkDevice, String8(""));
+
+ audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ struct audio_patch *patch = &sourceDesc->mPatchDesc->mPatch;
+
+ if (srcDeviceDesc->getAudioPort()->mModule->getHandle() ==
+ sinkDeviceDesc->getAudioPort()->mModule->getHandle() &&
+ srcDeviceDesc->getAudioPort()->mModule->getHalVersion() >= AUDIO_DEVICE_API_VERSION_3_0 &&
+ srcDeviceDesc->getAudioPort()->mGains.size() > 0) {
+ ALOGV("%s AUDIO_DEVICE_API_VERSION_3_0", __FUNCTION__);
+ // create patch between src device and output device
+ // create Hwoutput and add to mHwOutputs
+ } else {
+ SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(sinkDevice, mOutputs);
+ audio_io_handle_t output =
+ selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
+ if (output == AUDIO_IO_HANDLE_NONE) {
+ ALOGV("%s no output for device %08x", __FUNCTION__, sinkDevice);
+ return INVALID_OPERATION;
+ }
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
+ if (outputDesc->isDuplicated()) {
+ ALOGV("%s output for device %08x is duplicated", __FUNCTION__, sinkDevice);
+ return INVALID_OPERATION;
+ }
+ // create a special patch with no sink and two sources:
+ // - the second source indicates to PatchPanel through which output mix this patch should
+ // be connected as well as the stream type for volume control
+ // - the sink is defined by whatever output device is currently selected for the output
+ // though which this patch is routed.
+ patch->num_sinks = 0;
+ patch->num_sources = 2;
+ srcDeviceDesc->toAudioPortConfig(&patch->sources[0], NULL);
+ outputDesc->toAudioPortConfig(&patch->sources[1], NULL);
+ patch->sources[1].ext.mix.usecase.stream = stream;
+ status_t status = mpClientInterface->createAudioPatch(patch,
+ &afPatchHandle,
+ 0);
+ ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
+ status, afPatchHandle);
+ if (status != NO_ERROR) {
+ ALOGW("%s patch panel could not connect device patch, error %d",
+ __FUNCTION__, status);
+ return INVALID_OPERATION;
+ }
+ uint32_t delayMs = 0;
+ status = startSource(outputDesc, stream, sinkDevice, &delayMs);
+
+ if (status != NO_ERROR) {
+ mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
+ return status;
+ }
+ sourceDesc->mSwOutput = outputDesc;
+ if (delayMs != 0) {
+ usleep(delayMs * 1000);
+ }
+ }
+
+ sourceDesc->mPatchDesc->mAfPatchHandle = afPatchHandle;
+ addAudioPatch(sourceDesc->mPatchDesc->mHandle, sourceDesc->mPatchDesc);
+
+ return NO_ERROR;
}
status_t AudioPolicyManager::stopAudioSource(audio_io_handle_t handle __unused)
{
- return INVALID_OPERATION;
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
+ ALOGV("%s handle %d", __FUNCTION__, handle);
+ if (sourceDesc == 0) {
+ ALOGW("%s unknown source for handle %d", __FUNCTION__, handle);
+ return BAD_VALUE;
+ }
+ status_t status = disconnectAudioSource(sourceDesc);
+
+ mAudioSources.removeItem(handle);
+ return status;
+}
+
+status_t AudioPolicyManager::setMasterMono(bool mono)
+{
+ if (mMasterMono == mono) {
+ return NO_ERROR;
+ }
+ mMasterMono = mono;
+ // if enabling mono we close all offloaded devices, which will invalidate the
+ // corresponding AudioTrack. The AudioTrack client/MediaPlayer is responsible
+ // for recreating the new AudioTrack as non-offloaded PCM.
+ //
+ // If disabling mono, we leave all tracks as is: we don't know which clients
+ // and tracks are able to be recreated as offloaded. The next "song" should
+ // play back offloaded.
+ if (mMasterMono) {
+ Vector<audio_io_handle_t> offloaded;
+ for (size_t i = 0; i < mOutputs.size(); ++i) {
+ sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
+ if (desc->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
+ offloaded.push(desc->mIoHandle);
+ }
+ }
+ for (size_t i = 0; i < offloaded.size(); ++i) {
+ closeOutput(offloaded[i]);
+ }
+ }
+ // update master mono for all remaining outputs
+ for (size_t i = 0; i < mOutputs.size(); ++i) {
+ updateMono(mOutputs.keyAt(i));
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::getMasterMono(bool *mono)
+{
+ *mono = mMasterMono;
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+{
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+
+ sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->mPatchDesc->mHandle);
+ if (patchDesc == 0) {
+ ALOGW("%s source has no patch with handle %d", __FUNCTION__,
+ sourceDesc->mPatchDesc->mHandle);
+ return BAD_VALUE;
+ }
+ removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
+
+ audio_stream_type_t stream = audio_attributes_to_stream_type(&sourceDesc->mAttributes);
+ sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
+ if (swOutputDesc != 0) {
+ stopSource(swOutputDesc, stream, false);
+ mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
+ } else {
+ sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->mHwOutput.promote();
+ if (hwOutputDesc != 0) {
+ // release patch between src device and output device
+ // close Hwoutput and remove from mHwOutputs
+ } else {
+ ALOGW("%s source has neither SW nor HW output", __FUNCTION__);
+ }
+ }
+ return NO_ERROR;
+}
+
+sp<AudioSourceDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
+ audio_io_handle_t output, routing_strategy strategy)
+{
+ sp<AudioSourceDescriptor> source;
+ for (size_t i = 0; i < mAudioSources.size(); i++) {
+ sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ routing_strategy sourceStrategy =
+ (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
+ sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->mSwOutput.promote();
+ if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
+ source = sourceDesc;
+ break;
+ }
+ }
+ return source;
}
// ----------------------------------------------------------------------------
@@ -2721,7 +2990,8 @@
mBeaconMuteRefCount(0),
mBeaconPlayingRefCount(0),
mBeaconMuted(false),
- mTtsOutputAvailable(false)
+ mTtsOutputAvailable(false),
+ mMasterMono(false)
{
audio_policy::EngineInstance *engineInstance = audio_policy::EngineInstance::getInstance();
if (!engineInstance) {
@@ -2741,16 +3011,14 @@
mUidCached = getuid();
mpClientInterface = clientInterface;
- mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
- if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE,
- mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
- mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
- if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_CONFIG_FILE,
- mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
- mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
- ALOGE("could not load audio policy configuration file, setting defaults");
- defaultAudioPolicyConfig();
- }
+ AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,
+ mDefaultOutputDevice, mSpeakerDrcEnabled);
+
+ if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) &&
+ (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) {
+
+ ALOGE("could not load audio policy configuration file, setting defaults");
+ config.setDefault();
}
// mAvailableOutputDevices and mAvailableInputDevices now contain all attached devices
@@ -2761,9 +3029,9 @@
audio_devices_t outputDeviceTypes = mAvailableOutputDevices.types();
audio_devices_t inputDeviceTypes = mAvailableInputDevices.types() & ~AUDIO_DEVICE_BIT_IN;
for (size_t i = 0; i < mHwModules.size(); i++) {
- mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->mName);
+ mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName());
if (mHwModules[i]->mHandle == 0) {
- ALOGW("could not open HW module %s", mHwModules[i]->mName);
+ ALOGW("could not open HW module %s", mHwModules[i]->getName());
continue;
}
// open all output streams needed to access attached devices
@@ -2774,29 +3042,24 @@
{
const sp<IOProfile> outProfile = mHwModules[i]->mOutputProfiles[j];
- if (outProfile->mSupportedDevices.isEmpty()) {
- ALOGW("Output profile contains no device on module %s", mHwModules[i]->mName);
+ if (!outProfile->hasSupportedDevices()) {
+ ALOGW("Output profile contains no device on module %s", mHwModules[i]->getName());
continue;
}
- if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_TTS) != 0) {
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_TTS) != 0) {
mTtsOutputAvailable = true;
}
- if ((outProfile->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
+ if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
continue;
}
- audio_devices_t profileType = outProfile->mSupportedDevices.types();
+ audio_devices_t profileType = outProfile->getSupportedDevicesType();
if ((profileType & mDefaultOutputDevice->type()) != AUDIO_DEVICE_NONE) {
profileType = mDefaultOutputDevice->type();
} else {
- // chose first device present in mSupportedDevices also part of
+ // chose first device present in profile's SupportedDevices also part of
// outputDeviceTypes
- for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- profileType = outProfile->mSupportedDevices[k]->type();
- if ((profileType & outputDeviceTypes) != 0) {
- break;
- }
- }
+ profileType = outProfile->getSupportedDeviceForType(outputDeviceTypes);
}
if ((profileType & outputDeviceTypes) == 0) {
continue;
@@ -2821,23 +3084,22 @@
if (status != NO_ERROR) {
ALOGW("Cannot open output stream for device %08x on hw module %s",
outputDesc->mDevice,
- mHwModules[i]->mName);
+ mHwModules[i]->getName());
} else {
outputDesc->mSamplingRate = config.sample_rate;
outputDesc->mChannelMask = config.channel_mask;
outputDesc->mFormat = config.format;
- for (size_t k = 0; k < outProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = outProfile->mSupportedDevices[k]->type();
- ssize_t index =
- mAvailableOutputDevices.indexOf(outProfile->mSupportedDevices[k]);
+ const DeviceVector &supportedDevices = outProfile->getSupportedDevices();
+ for (size_t k = 0; k < supportedDevices.size(); k++) {
+ ssize_t index = mAvailableOutputDevices.indexOf(supportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
if (index >= 0 && !mAvailableOutputDevices[index]->isAttached()) {
mAvailableOutputDevices[index]->attach(mHwModules[i]);
}
}
if (mPrimaryOutput == 0 &&
- outProfile->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY) {
+ outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
mPrimaryOutput = outputDesc;
}
addOutput(output, outputDesc);
@@ -2852,25 +3114,20 @@
{
const sp<IOProfile> inProfile = mHwModules[i]->mInputProfiles[j];
- if (inProfile->mSupportedDevices.isEmpty()) {
- ALOGW("Input profile contains no device on module %s", mHwModules[i]->mName);
+ if (!inProfile->hasSupportedDevices()) {
+ ALOGW("Input profile contains no device on module %s", mHwModules[i]->getName());
continue;
}
- // chose first device present in mSupportedDevices also part of
+ // chose first device present in profile's SupportedDevices also part of
// inputDeviceTypes
- audio_devices_t profileType = AUDIO_DEVICE_NONE;
- for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- profileType = inProfile->mSupportedDevices[k]->type();
- if (profileType & inputDeviceTypes) {
- break;
- }
- }
+ audio_devices_t profileType = inProfile->getSupportedDeviceForType(inputDeviceTypes);
+
if ((profileType & inputDeviceTypes) == 0) {
continue;
}
- sp<AudioInputDescriptor> inputDesc = new AudioInputDescriptor(inProfile);
+ sp<AudioInputDescriptor> inputDesc =
+ new AudioInputDescriptor(inProfile);
- inputDesc->mInputSource = AUDIO_SOURCE_MIC;
inputDesc->mDevice = profileType;
// find the address
@@ -2895,10 +3152,9 @@
AUDIO_INPUT_FLAG_NONE);
if (status == NO_ERROR) {
- for (size_t k = 0; k < inProfile->mSupportedDevices.size(); k++) {
- audio_devices_t type = inProfile->mSupportedDevices[k]->type();
- ssize_t index =
- mAvailableInputDevices.indexOf(inProfile->mSupportedDevices[k]);
+ const DeviceVector &supportedDevices = inProfile->getSupportedDevices();
+ for (size_t k = 0; k < supportedDevices.size(); k++) {
+ ssize_t index = mAvailableInputDevices.indexOf(supportedDevices[k]);
// give a valid ID to an attached device once confirmed it is reachable
if (index >= 0) {
sp<DeviceDescriptor> devDesc = mAvailableInputDevices[index];
@@ -2912,14 +3168,14 @@
} else {
ALOGW("Cannot open input stream for device %08x on hw module %s",
inputDesc->mDevice,
- mHwModules[i]->mName);
+ mHwModules[i]->getName());
}
}
}
// make sure all attached devices have been allocated a unique ID
for (size_t i = 0; i < mAvailableOutputDevices.size();) {
if (!mAvailableOutputDevices[i]->isAttached()) {
- ALOGW("Input device %08x unreachable", mAvailableOutputDevices[i]->type());
+ ALOGW("Output device %08x unreachable", mAvailableOutputDevices[i]->type());
mAvailableOutputDevices.remove(mAvailableOutputDevices[i]);
continue;
}
@@ -2940,7 +3196,7 @@
i++;
}
// make sure default device is reachable
- if (mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
+ if (mDefaultOutputDevice == 0 || mAvailableOutputDevices.indexOf(mDefaultOutputDevice) < 0) {
ALOGE("Default device %08x is unreachable", mDefaultOutputDevice->type());
}
@@ -3160,6 +3416,7 @@
{
outputDesc->setIoHandle(output);
mOutputs.add(output, outputDesc);
+ updateMono(output); // update mono status when adding to output list
nextAudioPortGeneration();
}
@@ -3180,7 +3437,7 @@
const String8 address /*in*/,
SortedVector<audio_io_handle_t>& outputs /*out*/) {
sp<DeviceDescriptor> devDesc =
- desc->mProfile->mSupportedDevices.getDevice(device, address);
+ desc->mProfile->getSupportedDeviceByAddress(device, address);
if (devDesc != 0) {
ALOGV("findIoHandlesByAddress(): adding opened output %d on same address %s",
desc->mIoHandle, address.string());
@@ -3225,9 +3482,9 @@
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
- if (profile->mSupportedDevices.types() & device) {
+ if (profile->supportDevice(device)) {
if (!device_distinguishes_on_address(device) ||
- address == profile->mSupportedDevices[0]->mAddress) {
+ profile->supportDeviceAddress(address)) {
profiles.add(profile);
ALOGV("checkOutputsForDevice(): adding profile %zu from module %zu", j, i);
}
@@ -3235,7 +3492,7 @@
}
}
- ALOGV(" found %d profiles, %d outputs", profiles.size(), outputs.size());
+ ALOGV(" found %zu profiles, %zu outputs", profiles.size(), outputs.size());
if (profiles.isEmpty() && outputs.isEmpty()) {
ALOGW("checkOutputsForDevice(): No output available for device %04x", device);
@@ -3294,55 +3551,14 @@
mpClientInterface->setParameters(output, String8(param));
free(param);
}
-
- // Here is where we step through and resolve any "dynamic" fields
- String8 reply;
- char *value;
- if (profile->mSamplingRates[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkOutputsForDevice() supported sampling rates %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadSamplingRates(value + 1);
- }
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkOutputsForDevice() supported formats %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadFormats(value + 1);
- }
- }
- if (profile->mChannelMasks[0] == 0) {
- reply = mpClientInterface->getParameters(output,
- String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkOutputsForDevice() supported channel masks %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadOutChannels(value + 1);
- }
- }
- if (((profile->mSamplingRates[0] == 0) &&
- (profile->mSamplingRates.size() < 2)) ||
- ((profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) &&
- (profile->mFormats.size() < 2)) ||
- ((profile->mChannelMasks[0] == 0) &&
- (profile->mChannelMasks.size() < 2))) {
+ updateAudioProfiles(output, profile->getAudioProfiles());
+ if (!profile->hasValidAudioProfile()) {
ALOGW("checkOutputsForDevice() missing param");
mpClientInterface->closeOutput(output);
output = AUDIO_IO_HANDLE_NONE;
- } else if (profile->mSamplingRates[0] == 0 || profile->mFormats[0] == 0 ||
- profile->mChannelMasks[0] == 0) {
+ } else if (profile->hasDynamicAudioProfile()) {
mpClientInterface->closeOutput(output);
- config.sample_rate = profile->pickSamplingRate();
- config.channel_mask = profile->pickChannelMask();
- config.format = profile->pickFormat();
+ profile->pickAudioProfile(config.sample_rate, config.channel_mask, config.format);
config.offload_info.sample_rate = config.sample_rate;
config.offload_info.channel_mask = config.channel_mask;
config.offload_info.format = config.format;
@@ -3463,21 +3679,10 @@
for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++)
{
sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
- if (profile->mSupportedDevices.types() & device) {
+ if (profile->supportDevice(device)) {
ALOGV("checkOutputsForDevice(): "
"clearing direct output profile %zu on module %zu", j, i);
- if (profile->mSamplingRates[0] == 0) {
- profile->mSamplingRates.clear();
- profile->mSamplingRates.add(0);
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.clear();
- profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
- }
- if (profile->mChannelMasks[0] == 0) {
- profile->mChannelMasks.clear();
- profile->mChannelMasks.add(0);
- }
+ profile->clearAudioProfiles();
}
}
}
@@ -3502,7 +3707,7 @@
// first list already open inputs that can be routed to this device
for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
desc = mInputs.valueAt(input_index);
- if (desc->mProfile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ if (desc->mProfile->supportDevice(device)) {
ALOGV("checkInputsForDevice(): adding opened input %d", mInputs.keyAt(input_index));
inputs.add(mInputs.keyAt(input_index));
}
@@ -3521,9 +3726,9 @@
{
sp<IOProfile> profile = mHwModules[module_idx]->mInputProfiles[profile_index];
- if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ if (profile->supportDevice(device)) {
if (!device_distinguishes_on_address(device) ||
- address == profile->mSupportedDevices[0]->mAddress) {
+ profile->supportDeviceAddress(address)) {
profiles.add(profile);
ALOGV("checkInputsForDevice(): adding profile %zu from module %zu",
profile_index, module_idx);
@@ -3583,42 +3788,8 @@
mpClientInterface->setParameters(input, String8(param));
free(param);
}
-
- // Here is where we step through and resolve any "dynamic" fields
- String8 reply;
- char *value;
- if (profile->mSamplingRates[0] == 0) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES));
- ALOGV("checkInputsForDevice() direct input sup sampling rates %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadSamplingRates(value + 1);
- }
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
- ALOGV("checkInputsForDevice() direct input sup formats %s", reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadFormats(value + 1);
- }
- }
- if (profile->mChannelMasks[0] == 0) {
- reply = mpClientInterface->getParameters(input,
- String8(AUDIO_PARAMETER_STREAM_SUP_CHANNELS));
- ALOGV("checkInputsForDevice() direct input sup channel masks %s",
- reply.string());
- value = strpbrk((char *)reply.string(), "=");
- if (value != NULL) {
- profile->loadInChannels(value + 1);
- }
- }
- if (((profile->mSamplingRates[0] == 0) && (profile->mSamplingRates.size() < 2)) ||
- ((profile->mFormats[0] == 0) && (profile->mFormats.size() < 2)) ||
- ((profile->mChannelMasks[0] == 0) && (profile->mChannelMasks.size() < 2))) {
+ updateAudioProfiles(input, profile->getAudioProfiles());
+ if (!profile->hasValidAudioProfile()) {
ALOGW("checkInputsForDevice() direct input missing param");
mpClientInterface->closeInput(input);
input = AUDIO_IO_HANDLE_NONE;
@@ -3651,8 +3822,7 @@
// check if one opened input is not needed any more after disconnecting one device
for (size_t input_index = 0; input_index < mInputs.size(); input_index++) {
desc = mInputs.valueAt(input_index);
- if (!(desc->mProfile->mSupportedDevices.types() & mAvailableInputDevices.types() &
- ~AUDIO_DEVICE_BIT_IN)) {
+ if (!(desc->mProfile->supportDevice(mAvailableInputDevices.types()))) {
ALOGV("checkInputsForDevice(): disconnecting adding input %d",
mInputs.keyAt(input_index));
inputs.add(mInputs.keyAt(input_index));
@@ -3667,21 +3837,10 @@
profile_index < mHwModules[module_index]->mInputProfiles.size();
profile_index++) {
sp<IOProfile> profile = mHwModules[module_index]->mInputProfiles[profile_index];
- if (profile->mSupportedDevices.types() & (device & ~AUDIO_DEVICE_BIT_IN)) {
+ if (profile->supportDevice(device)) {
ALOGV("checkInputsForDevice(): clearing direct input profile %zu on module %zu",
profile_index, module_index);
- if (profile->mSamplingRates[0] == 0) {
- profile->mSamplingRates.clear();
- profile->mSamplingRates.add(0);
- }
- if (profile->mFormats[0] == AUDIO_FORMAT_DEFAULT) {
- profile->mFormats.clear();
- profile->mFormats.add(AUDIO_FORMAT_DEFAULT);
- }
- if (profile->mChannelMasks[0] == 0) {
- profile->mChannelMasks.clear();
- profile->mChannelMasks.add(0);
- }
+ profile->clearAudioProfiles();
}
}
}
@@ -3841,6 +4000,11 @@
setStrategyMute(strategy, true, desc);
setStrategyMute(strategy, false, desc, MUTE_TIME_MS, newDevice);
}
+ sp<AudioSourceDescriptor> source =
+ getSourceForStrategyOnOutput(srcOutputs[i], strategy);
+ if (source != 0){
+ connectAudioSource(source);
+ }
}
// Move effects associated to this strategy from previous output to new output
@@ -4012,7 +4176,7 @@
}
}
- audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->mInputSource);
+ audio_devices_t device = getDeviceAndMixForInputSource(inputDesc->inputSource());
return device;
}
@@ -4424,7 +4588,7 @@
// AUDIO_SOURCE_HOTWORD is for internal use only:
// handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
- !inputDesc->mIsSoundTrigger) {
+ !inputDesc->isSoundTrigger()) {
patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
}
patch.num_sinks = 1;
@@ -4779,39 +4943,6 @@
}
}
-
-
-void AudioPolicyManager::defaultAudioPolicyConfig(void)
-{
- sp<HwModule> module;
- sp<IOProfile> profile;
- sp<DeviceDescriptor> defaultInputDevice =
- new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
- mAvailableOutputDevices.add(mDefaultOutputDevice);
- mAvailableInputDevices.add(defaultInputDevice);
-
- module = new HwModule("primary");
-
- profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SOURCE);
- profile->attach(module);
- profile->mSamplingRates.add(44100);
- profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
- profile->mChannelMasks.add(AUDIO_CHANNEL_OUT_STEREO);
- profile->mSupportedDevices.add(mDefaultOutputDevice);
- profile->mFlags = AUDIO_OUTPUT_FLAG_PRIMARY;
- module->mOutputProfiles.add(profile);
-
- profile = new IOProfile(String8("primary"), AUDIO_PORT_ROLE_SINK);
- profile->attach(module);
- profile->mSamplingRates.add(8000);
- profile->mFormats.add(AUDIO_FORMAT_PCM_16_BIT);
- profile->mChannelMasks.add(AUDIO_CHANNEL_IN_MONO);
- profile->mSupportedDevices.add(defaultInputDevice);
- module->mInputProfiles.add(profile);
-
- mHwModules.add(module);
-}
-
audio_stream_type_t AudioPolicyManager::streamTypefromAttributesInt(const audio_attributes_t *attr)
{
// flags to stream type mapping
@@ -4935,4 +5066,85 @@
return is_state_in_call(state);
}
+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());
+ }
+ }
+
+ for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) {
+ sp<AudioPatch> patchDesc = mAudioPatches.valueAt(i);
+ bool release = false;
+ for (size_t j = 0; j < patchDesc->mPatch.num_sources && !release; j++) {
+ const struct audio_port_config *source = &patchDesc->mPatch.sources[j];
+ if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+ source->ext.device.type == deviceDesc->type()) {
+ release = true;
+ }
+ }
+ for (size_t j = 0; j < patchDesc->mPatch.num_sinks && !release; j++) {
+ const struct audio_port_config *sink = &patchDesc->mPatch.sinks[j];
+ if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+ sink->ext.device.type == deviceDesc->type()) {
+ release = true;
+ }
+ }
+ if (release) {
+ ALOGV("%s releasing patch %u", __FUNCTION__, patchDesc->mHandle);
+ releaseAudioPatch(patchDesc->mHandle, patchDesc->mUid);
+ }
+ }
+}
+
+void AudioPolicyManager::updateAudioProfiles(audio_io_handle_t ioHandle,
+ AudioProfileVector &profiles)
+{
+ String8 reply;
+ char *value;
+ // Format MUST be checked first to update the list of AudioProfile
+ if (profiles.hasDynamicFormat()) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ String8(AUDIO_PARAMETER_STREAM_SUP_FORMATS));
+ ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value == NULL) {
+ ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
+ return;
+ }
+ profiles.setFormats(formatsFromString(value + 1));
+ }
+ const FormatVector &supportedFormats = profiles.getSupportedFormats();
+
+ for(size_t formatIndex = 0; formatIndex < supportedFormats.size(); formatIndex++) {
+ audio_format_t format = supportedFormats[formatIndex];
+ AudioParameter requestedParameters;
+ requestedParameters.addInt(String8(AUDIO_PARAMETER_STREAM_FORMAT), format);
+
+ if (profiles.hasDynamicRateFor(format)) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ requestedParameters.toString() + ";" +
+ AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES);
+ ALOGV("%s: supported sampling rates %s", __FUNCTION__, reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ profiles.setSampleRatesFor(samplingRatesFromString(value + 1), format);
+ }
+ }
+ if (profiles.hasDynamicChannelsFor(format)) {
+ reply = mpClientInterface->getParameters(ioHandle,
+ requestedParameters.toString() + ";" +
+ AUDIO_PARAMETER_STREAM_SUP_CHANNELS);
+ ALOGV("%s: supported channel masks %s", __FUNCTION__, reply.string());
+ value = strpbrk((char *)reply.string(), "=");
+ if (value != NULL) {
+ profiles.setChannelsFor(channelMasksFromString(value + 1), format);
+ }
+ }
+ }
+}
+
}; // namespace android
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index bbdf396..37faac2 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -24,6 +24,7 @@
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/SortedVector.h>
+#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
#include "AudioPolicyInterface.h"
@@ -211,6 +212,8 @@
unsigned int *generation);
virtual status_t setAudioPortConfig(const struct audio_port_config *config);
+ virtual void releaseResourcesForUid(uid_t uid);
+
virtual status_t acquireSoundTriggerSession(audio_session_t *session,
audio_io_handle_t *ioHandle,
audio_devices_t *device);
@@ -225,10 +228,12 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_io_handle_t *handle);
+ audio_io_handle_t *handle,
+ uid_t uid);
virtual status_t stopAudioSource(audio_io_handle_t handle);
- virtual void releaseResourcesForUid(uid_t uid);
+ virtual status_t setMasterMono(bool mono);
+ virtual status_t getMasterMono(bool *mono);
// Audio policy configuration file parsing (audio_policy.conf)
// TODO candidates to be moved to ConfigParsingUtils
@@ -498,6 +503,17 @@
status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
+ status_t connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+ status_t disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+
+ sp<AudioSourceDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
+ routing_strategy strategy);
+
+ void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
+
+ void clearAudioSources(uid_t uid);
+
+
uid_t mUidCached;
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
@@ -537,6 +553,9 @@
sp<AudioPatch> mCallTxPatch;
sp<AudioPatch> mCallRxPatch;
+ HwAudioOutputCollection mHwOutputs;
+ AudioSourceCollection 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
enum {
@@ -550,6 +569,7 @@
bool mBeaconMuted; // has STREAM_TTS been muted
bool mTtsOutputAvailable; // true if a dedicated output for TTS stream is available
+ bool mMasterMono; // true if we wish to force all outputs to mono
AudioPolicyMixCollection mPolicyMixes; // list of registered mixes
#ifdef AUDIO_POLICY_TEST
@@ -572,6 +592,9 @@
// Audio Policy Engine Interface.
AudioPolicyManagerInterface *mEngine;
private:
+ // If any, resolve any "dynamic" fields of an Audio Profiles collection
+ void updateAudioProfiles(audio_io_handle_t ioHandle, AudioProfileVector &profiles);
+
// updates device caching and output for streams that can influence the
// routing of notifications
void handleNotificationRoutingForStream(audio_stream_type_t stream);
@@ -595,6 +618,18 @@
audio_channel_mask_t channelMask,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo);
+ // internal method to return the input handle for the given device and format
+ audio_io_handle_t getInputForDevice(audio_devices_t device,
+ String8 address,
+ audio_session_t session,
+ uid_t uid,
+ audio_source_t inputSource,
+ uint32_t samplingRate,
+ audio_format_t format,
+ audio_channel_mask_t channelMask,
+ audio_input_flags_t flags,
+ AudioMix *policyMix);
+
// internal function to derive a stream type value from audio attributes
audio_stream_type_t streamTypefromAttributesInt(const audio_attributes_t *attr);
// event is one of STARTING_OUTPUT, STARTING_BEACON, STOPPING_OUTPUT, STOPPING_BEACON
@@ -614,6 +649,11 @@
audio_policy_dev_state_t state,
const char *device_address,
const char *device_name);
+ void updateMono(audio_io_handle_t output) {
+ AudioParameter param;
+ param.addInt(String8(AUDIO_PARAMETER_MONO_OUTPUT), (int)mMasterMono);
+ mpClientInterface->setParameters(output, param.toString());
+ }
};
};
diff --git a/services/audiopolicy/service/AudioPolicyClientImpl.cpp b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
index 489a9be..3d51f48 100644
--- a/services/audiopolicy/service/AudioPolicyClientImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyClientImpl.cpp
@@ -219,6 +219,12 @@
mAudioPolicyService->onDynamicPolicyMixStateUpdate(regId, state);
}
+void AudioPolicyService::AudioPolicyClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source)
+{
+ mAudioPolicyService->onRecordingConfigurationUpdate(event, session, source);
+}
+
audio_unique_id_t AudioPolicyService::AudioPolicyClient::newAudioUniqueId()
{
return AudioSystem::newAudioUniqueId();
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index 282ddeb..f6f8276 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -323,7 +323,8 @@
VOICE_CALL_SRC_TAG,
CAMCORDER_SRC_TAG,
VOICE_REC_SRC_TAG,
- VOICE_COMM_SRC_TAG
+ VOICE_COMM_SRC_TAG,
+ UNPROCESSED_SRC_TAG
};
// returns the audio_source_t enum corresponding to the input source name or
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index a228798..c7486a5 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -164,13 +164,11 @@
ALOGV("getOutput()");
Mutex::Autolock _l(mLock);
- // if the caller is us, trust the specified uid
- if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
- uid_t newclientUid = IPCThreadState::self()->getCallingUid();
- if (uid != (uid_t)-1 && uid != newclientUid) {
- ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
- }
- uid = newclientUid;
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+ ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+ uid = callingUid;
}
return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate,
format, channelMask, flags, selectedDeviceId, offloadInfo);
@@ -284,13 +282,11 @@
sp<AudioPolicyEffects>audioPolicyEffects;
status_t status;
AudioPolicyInterface::input_type_t inputType;
- // if the caller is us, trust the specified uid
- if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) {
- uid_t newclientUid = IPCThreadState::self()->getCallingUid();
- if (uid != (uid_t)-1 && uid != newclientUid) {
- ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid);
- }
- uid = newclientUid;
+ const uid_t callingUid = IPCThreadState::self()->getCallingUid();
+ if (!isTrustedCallingUid(callingUid) || uid == (uid_t)-1) {
+ ALOGW_IF(uid != (uid_t)-1 && uid != callingUid,
+ "%s uid %d tried to pass itself off as %d", __FUNCTION__, callingUid, uid);
+ uid = callingUid;
}
{
@@ -564,7 +560,7 @@
ALOGV("mAudioPolicyManager == NULL");
return false;
}
-
+ Mutex::Autolock _l(mLock);
return mAudioPolicyManager->isOffloadSupported(info);
}
@@ -690,7 +686,8 @@
return NO_INIT;
}
- return mAudioPolicyManager->startAudioSource(source, attributes, handle);
+ return mAudioPolicyManager->startAudioSource(source, attributes, handle,
+ IPCThreadState::self()->getCallingUid());
}
status_t AudioPolicyService::stopAudioSource(audio_io_handle_t handle)
@@ -703,4 +700,25 @@
return mAudioPolicyManager->stopAudioSource(handle);
}
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!settingsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->setMasterMono(mono);
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ Mutex::Autolock _l(mLock);
+ return mAudioPolicyManager->getMasterMono(mono);
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
index 13af3ef..08b2a3b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp
@@ -619,4 +619,14 @@
return INVALID_OPERATION;
}
+status_t AudioPolicyService::setMasterMono(bool mono)
+{
+ return INVALID_OPERATION;
+}
+
+status_t AudioPolicyService::getMasterMono(bool *mono)
+{
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index c77cc45..0c5d275 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -149,7 +149,10 @@
// connects to AudioPolicyService.
void AudioPolicyService::registerClient(const sp<IAudioPolicyServiceClient>& client)
{
-
+ if (client == 0) {
+ ALOGW("%s got NULL client", __FUNCTION__);
+ return;
+ }
Mutex::Autolock _l(mNotificationClientsLock);
uid_t uid = IPCThreadState::self()->getCallingUid();
@@ -212,19 +215,6 @@
mOutputCommandThread->updateAudioPatchListCommand();
}
-status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
- audio_patch_handle_t *handle,
- int delayMs)
-{
- return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
-}
-
-status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
- int delayMs)
-{
- return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
-}
-
void AudioPolicyService::doOnAudioPatchListUpdate()
{
Mutex::Autolock _l(mNotificationClientsLock);
@@ -248,6 +238,34 @@
}
}
+void AudioPolicyService::onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source)
+{
+ mOutputCommandThread->recordingConfigurationUpdateCommand(event, session, source);
+}
+
+void AudioPolicyService::doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source)
+{
+ Mutex::Autolock _l(mNotificationClientsLock);
+ for (size_t i = 0; i < mNotificationClients.size(); i++) {
+ mNotificationClients.valueAt(i)->onRecordingConfigurationUpdate(event, session, source);
+ }
+}
+
+status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
+ audio_patch_handle_t *handle,
+ int delayMs)
+{
+ return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
+}
+
+status_t AudioPolicyService::clientReleaseAudioPatch(audio_patch_handle_t handle,
+ int delayMs)
+{
+ return mAudioCommandThread->releaseAudioPatchCommand(handle, delayMs);
+}
+
status_t AudioPolicyService::clientSetAudioPortConfig(const struct audio_port_config *config,
int delayMs)
{
@@ -293,7 +311,15 @@
String8 regId, int32_t state)
{
if (mAudioPolicyServiceClient != 0) {
- mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+ mAudioPolicyServiceClient->onDynamicPolicyMixStateUpdate(regId, state);
+ }
+}
+
+void AudioPolicyService::NotificationClient::onRecordingConfigurationUpdate(
+ int event, audio_session_t session, audio_source_t source)
+{
+ if (mAudioPolicyServiceClient != 0) {
+ mAudioPolicyServiceClient->onRecordingConfigurationUpdate(event, session, source);
}
}
@@ -555,7 +581,6 @@
case DYN_POLICY_MIX_STATE_UPDATE: {
DynPolicyMixStateUpdateData *data =
(DynPolicyMixStateUpdateData *)command->mParam.get();
- //###ALOGV("AudioCommandThread() processing dyn policy mix state update");
ALOGV("AudioCommandThread() processing dyn policy mix state update %s %d",
data->mRegId.string(), data->mState);
svc = mService.promote();
@@ -566,6 +591,19 @@
svc->doOnDynamicPolicyMixStateUpdate(data->mRegId, data->mState);
mLock.lock();
} break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+ RecordingConfigurationUpdateData *data =
+ (RecordingConfigurationUpdateData *)command->mParam.get();
+ ALOGV("AudioCommandThread() processing recording configuration update");
+ svc = mService.promote();
+ if (svc == 0) {
+ break;
+ }
+ mLock.unlock();
+ svc->doOnRecordingConfigurationUpdate(data->mEvent, data->mSession,
+ data->mSource);
+ mLock.lock();
+ } break;
default:
ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
}
@@ -822,6 +860,21 @@
sendCommand(command);
}
+void AudioPolicyService::AudioCommandThread::recordingConfigurationUpdateCommand(
+ int event, audio_session_t session, audio_source_t source)
+{
+ sp<AudioCommand>command = new AudioCommand();
+ command->mCommand = RECORDING_CONFIGURATION_UPDATE;
+ RecordingConfigurationUpdateData *data = new RecordingConfigurationUpdateData();
+ data->mEvent = event;
+ data->mSession = session;
+ data->mSource = source;
+ command->mParam = data;
+ ALOGV("AudioCommandThread() adding recording configuration update event %d, source %d",
+ event, source);
+ sendCommand(command);
+}
+
status_t AudioPolicyService::AudioCommandThread::sendCommand(sp<AudioCommand>& command, int delayMs)
{
{
@@ -968,6 +1021,10 @@
} break;
+ case RECORDING_CONFIGURATION_UPDATE: {
+
+ } break;
+
case START_TONE:
case STOP_TONE:
default:
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index a0d5aa2..160f4f0 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -202,6 +202,9 @@
audio_io_handle_t *handle);
virtual status_t stopAudioSource(audio_io_handle_t handle);
+ virtual status_t setMasterMono(bool mono);
+ virtual status_t getMasterMono(bool *mono);
+
status_t doStopOutput(audio_io_handle_t output,
audio_stream_type_t stream,
audio_session_t session);
@@ -225,6 +228,10 @@
void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
void doOnDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ void onRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
+ void doOnRecordingConfigurationUpdate(int event, audio_session_t session,
+ audio_source_t source);
private:
AudioPolicyService() ANDROID_API;
@@ -256,7 +263,8 @@
UPDATE_AUDIOPORT_LIST,
UPDATE_AUDIOPATCH_LIST,
SET_AUDIOPORT_CONFIG,
- DYN_POLICY_MIX_STATE_UPDATE
+ DYN_POLICY_MIX_STATE_UPDATE,
+ RECORDING_CONFIGURATION_UPDATE
};
AudioCommandThread (String8 name, const wp<AudioPolicyService>& service);
@@ -295,6 +303,9 @@
status_t setAudioPortConfigCommand(const struct audio_port_config *config,
int delayMs);
void dynamicPolicyMixStateUpdateCommand(String8 regId, int32_t state);
+ void recordingConfigurationUpdateCommand(
+ int event, audio_session_t session,
+ audio_source_t source);
void insertCommand_l(AudioCommand *command, int delayMs = 0);
private:
@@ -385,6 +396,13 @@
int32_t mState;
};
+ class RecordingConfigurationUpdateData : public AudioCommandData {
+ public:
+ int mEvent;
+ audio_session_t mSession;
+ audio_source_t mSource;
+ };
+
Mutex mLock;
Condition mWaitWorkCV;
Vector < sp<AudioCommand> > mAudioCommands; // list of pending commands
@@ -491,6 +509,8 @@
virtual void onAudioPortListUpdate();
virtual void onAudioPatchListUpdate();
virtual void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ virtual void onRecordingConfigurationUpdate(int event,
+ audio_session_t session, audio_source_t source);
virtual audio_unique_id_t newAudioUniqueId();
@@ -509,6 +529,9 @@
void onAudioPortListUpdate();
void onAudioPatchListUpdate();
void onDynamicPolicyMixStateUpdate(String8 regId, int32_t state);
+ void onRecordingConfigurationUpdate(
+ int event, audio_session_t session,
+ audio_source_t source);
void setAudioPortCallbacksEnabled(bool enabled);
// IBinder::DeathRecipient
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 45900c4..9ba8f3f 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -22,7 +22,6 @@
LOCAL_SRC_FILES:= \
CameraService.cpp \
- CameraDeviceFactory.cpp \
CameraFlashlight.cpp \
common/Camera2ClientBase.cpp \
common/CameraDeviceBase.cpp \
@@ -35,14 +34,10 @@
api1/client2/StreamingProcessor.cpp \
api1/client2/JpegProcessor.cpp \
api1/client2/CallbackProcessor.cpp \
- api1/client2/ZslProcessor.cpp \
- api1/client2/ZslProcessorInterface.cpp \
- api1/client2/BurstCapture.cpp \
api1/client2/JpegCompressor.cpp \
api1/client2/CaptureSequencer.cpp \
- api1/client2/ZslProcessor3.cpp \
+ api1/client2/ZslProcessor.cpp \
api2/CameraDeviceClient.cpp \
- device2/Camera2Device.cpp \
device3/Camera3Device.cpp \
device3/Camera3Stream.cpp \
device3/Camera3IOStreamBase.cpp \
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.cpp b/services/camera/libcameraservice/CameraDeviceFactory.cpp
deleted file mode 100644
index 6589e27..0000000
--- a/services/camera/libcameraservice/CameraDeviceFactory.cpp
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-// #define LOG_NDEBUG 0
-#define LOG_TAG "CameraDeviceFactory"
-#include <utils/Log.h>
-
-#include "CameraService.h"
-#include "CameraDeviceFactory.h"
-#include "common/CameraDeviceBase.h"
-#include "device2/Camera2Device.h"
-#include "device3/Camera3Device.h"
-
-namespace android {
-
-wp<CameraService> CameraDeviceFactory::sService;
-
-sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) {
-
- sp<CameraService> svc = sService.promote();
- if (svc == 0) {
- ALOGE("%s: No service registered", __FUNCTION__);
- return NULL;
- }
-
- int deviceVersion = svc->getDeviceVersion(cameraId, /*facing*/NULL);
-
- sp<CameraDeviceBase> device;
-
- switch (deviceVersion) {
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
- device = new Camera2Device(cameraId);
- break;
- case CAMERA_DEVICE_API_VERSION_3_0:
- case CAMERA_DEVICE_API_VERSION_3_1:
- case CAMERA_DEVICE_API_VERSION_3_2:
- case CAMERA_DEVICE_API_VERSION_3_3:
- device = new Camera3Device(cameraId);
- break;
- default:
- ALOGE("%s: Camera %d: Unknown HAL device version %d",
- __FUNCTION__, cameraId, deviceVersion);
- device = NULL;
- break;
- }
-
- ALOGV_IF(device != 0, "Created a new camera device for version %d",
- deviceVersion);
-
- return device;
-}
-
-void CameraDeviceFactory::registerService(wp<CameraService> service) {
- ALOGV("%s: Registered service %p", __FUNCTION__,
- service.promote().get());
-
- sService = service;
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/CameraDeviceFactory.h b/services/camera/libcameraservice/CameraDeviceFactory.h
deleted file mode 100644
index 236dc56..0000000
--- a/services/camera/libcameraservice/CameraDeviceFactory.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERADEVICEFACTORY_H
-#define ANDROID_SERVERS_CAMERA_CAMERADEVICEFACTORY_H
-
-#include <utils/RefBase.h>
-
-namespace android {
-
-class CameraDeviceBase;
-class CameraService;
-
-/**
- * Create the right instance of Camera2Device or Camera3Device
- * automatically based on the device version.
- */
-class CameraDeviceFactory : public virtual RefBase {
- public:
- static void registerService(wp<CameraService> service);
-
- // Prerequisite: Call registerService.
- static sp<CameraDeviceBase> createDevice(int cameraId);
- private:
- CameraDeviceFactory(wp<CameraService> service);
-
- static wp<CameraService> sService;
-};
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/CameraFlashlight.cpp b/services/camera/libcameraservice/CameraFlashlight.cpp
index 406c1c4..0afd945 100644
--- a/services/camera/libcameraservice/CameraFlashlight.cpp
+++ b/services/camera/libcameraservice/CameraFlashlight.cpp
@@ -27,7 +27,7 @@
#include "gui/IGraphicBufferConsumer.h"
#include "gui/BufferQueue.h"
#include "camera/camera2/CaptureRequest.h"
-#include "CameraDeviceFactory.h"
+#include "device3/Camera3Device.h"
namespace android {
@@ -78,7 +78,7 @@
deviceVersion = info.device_version;
}
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_0) {
CameraDeviceClientFlashControl *flashControl =
new CameraDeviceClientFlashControl(*mCameraModule,
*mCallbacks);
@@ -193,8 +193,6 @@
}
bool CameraFlashlight::hasFlashUnit(const String8& cameraId) {
- status_t res;
-
Mutex::Autolock l(mLock);
return hasFlashUnitLocked(cameraId);
}
@@ -302,7 +300,8 @@
/////////////////////////////////////////////////////////////////////
ModuleFlashControl::ModuleFlashControl(CameraModule& cameraModule,
const camera_module_callbacks_t& callbacks) :
- mCameraModule(&cameraModule) {
+ mCameraModule(&cameraModule) {
+ (void) callbacks;
}
ModuleFlashControl::~ModuleFlashControl() {
@@ -478,7 +477,7 @@
}
sp<CameraDeviceBase> device =
- CameraDeviceFactory::createDevice(atoi(cameraId.string()));
+ new Camera3Device(atoi(cameraId.string()));
if (device == NULL) {
return NO_MEMORY;
}
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 3deb396..cf4da85 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -55,7 +55,6 @@
#include "api1/Camera2Client.h"
#include "api2/CameraDeviceClient.h"
#include "utils/CameraTraces.h"
-#include "CameraDeviceFactory.h"
namespace android {
@@ -153,6 +152,7 @@
ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));
logServiceError("Could not load camera HAL module", err);
mNumberOfCameras = 0;
+ mNumberOfNormalCameras = 0;
return;
}
@@ -246,8 +246,6 @@
mModule->setCallbacks(this);
}
- CameraDeviceFactory::registerService(this);
-
CameraService::pingCameraServiceProxy();
}
@@ -315,10 +313,8 @@
clientToDisconnect = removeClientLocked(id);
// Notify the client of disconnection
- if (clientToDisconnect != nullptr) {
- clientToDisconnect->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
- CaptureResultExtras{});
- }
+ clientToDisconnect->notifyError(ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
+ CaptureResultExtras{});
}
ALOGI("%s: Client for camera ID %s evicted due to device status change from HAL",
@@ -366,7 +362,8 @@
res = setTorchStatusLocked(cameraId, newStatus);
if (res) {
- ALOGE("%s: Failed to set the torch status", __FUNCTION__, (uint32_t)newStatus);
+ ALOGE("%s: Failed to set the torch status to %d: %s (%d)", __FUNCTION__,
+ (uint32_t)newStatus, strerror(-res), res);
return;
}
@@ -483,7 +480,6 @@
Vector<Size> sizes;
Vector<Size> jpegSizes;
Vector<int32_t> formats;
- const char* supportedPreviewFormats;
{
shimParams.getSupportedPreviewSizes(/*out*/sizes);
shimParams.getSupportedPreviewFormats(/*out*/formats);
@@ -561,7 +557,7 @@
int facing;
status_t ret = OK;
if (mModule->getModuleApiVersion() < CAMERA_MODULE_API_VERSION_2_0 ||
- getDeviceVersion(cameraId, &facing) <= CAMERA_DEVICE_API_VERSION_2_1 ) {
+ getDeviceVersion(cameraId, &facing) < CAMERA_DEVICE_API_VERSION_3_0) {
/**
* Backwards compatibility mode for old HALs:
* - Convert CameraInfo into static CameraMetadata properties.
@@ -727,8 +723,6 @@
return -EOPNOTSUPP;
}
break;
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
@@ -887,18 +881,7 @@
return -ENODEV;
}
- // Check device policy for this camera
- char value[PROPERTY_VALUE_MAX];
- char key[PROPERTY_KEY_MAX];
userid_t clientUserId = multiuser_get_user_id(clientUid);
- snprintf(key, PROPERTY_KEY_MAX, "sys.secpolicy.camera.off_%d", clientUserId);
- property_get(key, value, "0");
- if (strcmp(value, "1") == 0) {
- // Camera is disabled by DevicePolicyManager.
- ALOGE("CameraService::connect X (PID %d) rejected (camera %s is disabled by device "
- "policy)", callingPid, cameraId.string());
- return -EACCES;
- }
// Only allow clients who are being used by the current foreground device user, unless calling
// from our own process.
@@ -1319,7 +1302,6 @@
// update the link to client's death
Mutex::Autolock al(mTorchClientMapMutex);
ssize_t index = mTorchClientMap.indexOfKey(id);
- BatteryNotifier& notifier(BatteryNotifier::getInstance());
if (enabled) {
if (index == NAME_NOT_FOUND) {
mTorchClientMap.add(id, clientBinder);
@@ -1476,8 +1458,6 @@
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
- case CAMERA_DEVICE_API_VERSION_2_0:
- case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
if (apiVersion == API_VERSION_2) {
@@ -1568,8 +1548,34 @@
/**
* Check camera capabilities, such as support for basic color operation
+ * Also check that the device HAL version is still in support
*/
int CameraService::checkCameraCapabilities(int id, camera_info info, int *latestStrangeCameraId) {
+ // device_version undefined in CAMERA_MODULE_API_VERSION_1_0,
+ // All CAMERA_MODULE_API_VERSION_1_0 devices are backward-compatible
+ if (mModule->getModuleApiVersion() >= CAMERA_MODULE_API_VERSION_2_0) {
+ // Verify the device version is in the supported range
+ switch (info.device_version) {
+ case CAMERA_DEVICE_API_VERSION_1_0:
+ case CAMERA_DEVICE_API_VERSION_3_0:
+ case CAMERA_DEVICE_API_VERSION_3_1:
+ case CAMERA_DEVICE_API_VERSION_3_2:
+ case CAMERA_DEVICE_API_VERSION_3_3:
+ // in support
+ break;
+ case CAMERA_DEVICE_API_VERSION_2_0:
+ case CAMERA_DEVICE_API_VERSION_2_1:
+ // no longer supported
+ default:
+ ALOGE("%s: Device %d has HAL version %x, which is not supported",
+ __FUNCTION__, id, info.device_version);
+ String8 msg = String8::format(
+ "Unsupported device HAL version %x for device %d",
+ info.device_version, id);
+ logServiceError(msg.string(), NO_INIT);
+ return NO_INIT;
+ }
+ }
// Assume all devices pre-v3.3 are backward-compatible
bool isBackwardCompatible = true;
@@ -1604,10 +1610,10 @@
ALOGE("%s: Normal camera ID %d higher than strange camera ID %d. "
"This is not allowed due backward-compatibility requirements",
__FUNCTION__, id, *latestStrangeCameraId);
- logServiceError("Invalid order of camera devices", ENODEV);
+ logServiceError("Invalid order of camera devices", NO_INIT);
mNumberOfCameras = 0;
mNumberOfNormalCameras = 0;
- return INVALID_OPERATION;
+ return NO_INIT;
}
}
return OK;
@@ -1765,7 +1771,7 @@
void CameraService::logServiceError(const char* msg, int errorCode) {
String8 curTime = getFormattedCurrentTime();
- logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(errorCode)));
+ logEvent(String8::format("SERVICE ERROR: %s : %d (%s)", msg, errorCode, strerror(-errorCode)));
}
status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
@@ -2086,6 +2092,8 @@
void CameraService::Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras) {
+ (void) errorCode;
+ (void) resultExtras;
if (mRemoteCallback != NULL) {
mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
} else {
@@ -2353,7 +2361,7 @@
result.appendFormat(" Resource Cost: %d\n", state.second->getCost());
result.appendFormat(" Conflicting Devices:");
for (auto& id : conflicting) {
- result.appendFormat(" %s", cameraId.string());
+ result.appendFormat(" %s", id.string());
}
if (conflicting.size() == 0) {
result.appendFormat(" NONE");
@@ -2361,7 +2369,7 @@
result.appendFormat("\n");
result.appendFormat(" Device version: %#x\n", deviceVersion);
- if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
+ if (deviceVersion >= CAMERA_DEVICE_API_VERSION_3_0) {
result.appendFormat(" Device static metadata:\n");
write(fd, result.string(), result.size());
dump_indented_camera_metadata(info.static_camera_characteristics,
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 4b0eeb7..18b97a3 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -293,7 +293,7 @@
virtual status_t startPreview() = 0;
virtual void stopPreview() = 0;
virtual bool previewEnabled() = 0;
- virtual status_t storeMetaDataInBuffers(bool enabled) = 0;
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode) = 0;
virtual status_t startRecording() = 0;
virtual void stopRecording() = 0;
virtual bool recordingEnabled() = 0;
@@ -304,6 +304,7 @@
virtual status_t setParameters(const String8& params) = 0;
virtual String8 getParameters() const = 0;
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) = 0;
+ virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) = 0;
// Interface used by CameraService
Client(const sp<CameraService>& cameraService,
@@ -620,6 +621,7 @@
/**
* Add a event log message that a serious service-level error has occured
+ * The errorCode should be one of the Android Errors
*/
void logServiceError(const char* msg, int errorCode);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index 4338d64..6722512 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -32,7 +32,6 @@
#include "api1/client2/CaptureSequencer.h"
#include "api1/client2/CallbackProcessor.h"
#include "api1/client2/ZslProcessor.h"
-#include "api1/client2/ZslProcessor3.h"
#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -94,7 +93,6 @@
mStreamingProcessor = new StreamingProcessor(this);
threadName = String8::format("C2-%d-StreamProc",
mCameraId);
- mStreamingProcessor->run(threadName.string());
mFrameProcessor = new FrameProcessor(mDevice, this);
threadName = String8::format("C2-%d-FrameProc",
@@ -111,30 +109,11 @@
mCameraId);
mJpegProcessor->run(threadName.string());
- switch (mDeviceVersion) {
- case CAMERA_DEVICE_API_VERSION_2_0: {
- sp<ZslProcessor> zslProc =
- new ZslProcessor(this, mCaptureSequencer);
- mZslProcessor = zslProc;
- mZslProcessorThread = zslProc;
- break;
- }
- case CAMERA_DEVICE_API_VERSION_3_0:
- case CAMERA_DEVICE_API_VERSION_3_1:
- case CAMERA_DEVICE_API_VERSION_3_2:
- case CAMERA_DEVICE_API_VERSION_3_3: {
- sp<ZslProcessor3> zslProc =
- new ZslProcessor3(this, mCaptureSequencer);
- mZslProcessor = zslProc;
- mZslProcessorThread = zslProc;
- break;
- }
- default:
- break;
- }
+ mZslProcessor = new ZslProcessor(this, mCaptureSequencer);
+
threadName = String8::format("C2-%d-ZslProc",
mCameraId);
- mZslProcessorThread->run(threadName.string());
+ mZslProcessor->run(threadName.string());
mCallbackProcessor = new CallbackProcessor(this);
threadName = String8::format("C2-%d-CallbkProc",
@@ -410,11 +389,10 @@
l.mParameters.state = Parameters::DISCONNECTED;
}
- mStreamingProcessor->requestExit();
mFrameProcessor->requestExit();
mCaptureSequencer->requestExit();
mJpegProcessor->requestExit();
- mZslProcessorThread->requestExit();
+ mZslProcessor->requestExit();
mCallbackProcessor->requestExit();
ALOGV("Camera %d: Waiting for threads", mCameraId);
@@ -424,11 +402,10 @@
// complete callbacks that re-enter Camera2Client
mBinderSerializationLock.unlock();
- mStreamingProcessor->join();
mFrameProcessor->join();
mCaptureSequencer->join();
mJpegProcessor->join();
- mZslProcessorThread->join();
+ mZslProcessor->join();
mCallbackProcessor->join();
mBinderSerializationLock.lock();
@@ -442,9 +419,6 @@
mCallbackProcessor->deleteStream();
mZslProcessor->deleteStream();
- // Remove all ZSL stream state before disconnect; needed to work around b/15408128.
- mZslProcessor->disconnect();
-
ALOGV("Camera %d: Disconnecting device", mCameraId);
mDevice->disconnect();
@@ -761,8 +735,8 @@
// We could wait to create the JPEG output stream until first actual use
// (first takePicture call). However, this would substantially increase the
- // first capture latency on HAL3 devices, and potentially on some HAL2
- // devices. So create it unconditionally at preview start. As a drawback,
+ // first capture latency on HAL3 devices.
+ // So create it unconditionally at preview start. As a drawback,
// this increases gralloc memory consumption for applications that don't
// ever take a picture. Do not enter this mode when jpeg stream will slow
// down preview.
@@ -967,7 +941,7 @@
return l.mParameters.state == Parameters::PREVIEW;
}
-status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
+status_t Camera2Client::setVideoBufferMode(int32_t videoBufferMode) {
ATRACE_CALL();
Mutex::Autolock icl(mBinderSerializationLock);
status_t res;
@@ -986,7 +960,12 @@
break;
}
- l.mParameters.storeMetadataInBuffers = enabled;
+ if (videoBufferMode != VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ ALOGE("%s: %d: Only video buffer queue is supported", __FUNCTION__, __LINE__);
+ return BAD_VALUE;
+ }
+
+ l.mParameters.videoBufferMode = videoBufferMode;
return OK;
}
@@ -1032,10 +1011,14 @@
return INVALID_OPERATION;
};
- if (!params.storeMetadataInBuffers) {
- ALOGE("%s: Camera %d: Recording only supported in metadata mode, but "
- "non-metadata recording mode requested!", __FUNCTION__,
- mCameraId);
+ if (params.videoBufferMode != VIDEO_BUFFER_MODE_BUFFER_QUEUE) {
+ ALOGE("%s: Camera %d: Recording only supported buffer queue mode, but "
+ "mode %d is requested!", __FUNCTION__, mCameraId, params.videoBufferMode);
+ return INVALID_OPERATION;
+ }
+
+ if (!mStreamingProcessor->haveValidRecordingWindow()) {
+ ALOGE("%s: No valid recording window", __FUNCTION__);
return INVALID_OPERATION;
}
@@ -1069,35 +1052,33 @@
}
}
- // On current HALs, clean up ZSL before transitioning into recording
- if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
- if (mZslProcessor->getStreamId() != NO_STREAM) {
- ALOGV("%s: Camera %d: Clearing out zsl stream before "
- "creating recording stream", __FUNCTION__, mCameraId);
- res = mStreamingProcessor->stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
- __FUNCTION__, mCameraId);
- return res;
- }
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- res = mZslProcessor->clearZslQueue();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't clear zsl queue",
- __FUNCTION__, mCameraId);
- return res;
- }
- res = mZslProcessor->deleteStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to delete zsl stream before "
- "record: %s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- return res;
- }
+ // Clean up ZSL before transitioning into recording
+ if (mZslProcessor->getStreamId() != NO_STREAM) {
+ ALOGV("%s: Camera %d: Clearing out zsl stream before "
+ "creating recording stream", __FUNCTION__, mCameraId);
+ res = mStreamingProcessor->stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming to delete callback stream",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ res = mZslProcessor->clearZslQueue();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't clear zsl queue",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+ res = mZslProcessor->deleteStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete zsl stream before "
+ "record: %s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ return res;
}
}
@@ -1105,56 +1086,43 @@
// and we can't fail record start without stagefright asserting.
params.previewCallbackFlags = 0;
- if (mDeviceVersion != CAMERA_DEVICE_API_VERSION_2_0) {
- // For newer devices, may need to reconfigure video snapshot JPEG sizes
- // during recording startup, so need a more complex sequence here to
- // ensure an early stream reconfiguration doesn't happen
- bool recordingStreamNeedsUpdate;
- res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
+ // May need to reconfigure video snapshot JPEG sizes
+ // during recording startup, so need a more complex sequence here to
+ // ensure an early stream reconfiguration doesn't happen
+ bool recordingStreamNeedsUpdate;
+ res = mStreamingProcessor->recordingStreamNeedsUpdate(params, &recordingStreamNeedsUpdate);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't query recording stream",
+ __FUNCTION__, mCameraId);
+ return res;
+ }
+
+ if (recordingStreamNeedsUpdate) {
+ // Need to stop stream here so updateProcessorStream won't trigger configureStream
+ // Right now camera device cannot handle configureStream failure gracefully
+ // when device is streaming
+ res = mStreamingProcessor->stopStream();
if (res != OK) {
- ALOGE("%s: Camera %d: Can't query recording stream",
- __FUNCTION__, mCameraId);
+ ALOGE("%s: Camera %d: Can't stop streaming to update record "
+ "stream", __FUNCTION__, mCameraId);
return res;
}
-
- if (recordingStreamNeedsUpdate) {
- // Need to stop stream here so updateProcessorStream won't trigger configureStream
- // Right now camera device cannot handle configureStream failure gracefully
- // when device is streaming
- res = mStreamingProcessor->stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't stop streaming to update record "
- "stream", __FUNCTION__, mCameraId);
- return res;
- }
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Camera %d: Waiting to stop streaming failed: "
- "%s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- }
-
- res = updateProcessorStream<
- StreamingProcessor,
- &StreamingProcessor::updateRecordingStream>(
- mStreamingProcessor,
- params);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update recording stream: "
- "%s (%d)", __FUNCTION__, mCameraId,
- strerror(-res), res);
- return res;
- }
- }
- } else {
- // Maintain call sequencing for HALv2 devices.
- res = updateProcessorStream<
- StreamingProcessor,
- &StreamingProcessor::updateRecordingStream>(mStreamingProcessor,
- params);
+ res = mDevice->waitUntilDrained();
if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: "
+ "%s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
+ }
+
+ res = updateProcessorStream<
+ StreamingProcessor,
+ &StreamingProcessor::updateRecordingStream>(
+ mStreamingProcessor,
+ params);
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to update recording stream: "
+ "%s (%d)", __FUNCTION__, mCameraId,
+ strerror(-res), res);
return res;
}
}
@@ -1214,28 +1182,28 @@
mCameraService->playSound(CameraService::SOUND_RECORDING_STOP);
- // Remove recording stream to prevent it from slowing down takePicture later
- if (!l.mParameters.recordingHint && l.mParameters.isJpegSizeOverridden()) {
- res = stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- res = mDevice->waitUntilDrained();
- if (res != OK) {
- ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- // Clean up recording stream
- res = mStreamingProcessor->deleteRecordingStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to delete recording stream before "
- "stop preview: %s (%d)",
- __FUNCTION__, mCameraId, strerror(-res), res);
- }
- l.mParameters.recoverOverriddenJpegSize();
+ // Remove recording stream because the video target may be abandoned soon.
+ res = stopStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
}
+ res = mDevice->waitUntilDrained();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ // Clean up recording stream
+ res = mStreamingProcessor->deleteRecordingStream();
+ if (res != OK) {
+ ALOGE("%s: Camera %d: Unable to delete recording stream before "
+ "stop preview: %s (%d)",
+ __FUNCTION__, mCameraId, strerror(-res), res);
+ }
+ l.mParameters.recoverOverriddenJpegSize();
+
+ // Restart preview
res = startPreviewL(l.mParameters, true);
if (res != OK) {
ALOGE("%s: Camera %d: Unable to return to preview",
@@ -1262,10 +1230,7 @@
void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
ATRACE_CALL();
- Mutex::Autolock icl(mBinderSerializationLock);
- if ( checkPid(__FUNCTION__) != OK) return;
-
- mStreamingProcessor->releaseRecordingFrame(mem);
+ ALOGW("%s: Not supported in buffer queue mode.", __FUNCTION__);
}
status_t Camera2Client::autoFocus() {
@@ -1567,10 +1532,10 @@
case CAMERA_CMD_PING:
return commandPingL();
case CAMERA_CMD_SET_VIDEO_BUFFER_COUNT:
- return commandSetVideoBufferCountL(arg1);
case CAMERA_CMD_SET_VIDEO_FORMAT:
- return commandSetVideoFormatL(arg1,
- static_cast<android_dataspace>(arg2));
+ ALOGE("%s: command %d (arguments %d, %d) is not supported.",
+ __FUNCTION__, cmd, arg1, arg2);
+ return BAD_VALUE;
default:
ALOGE("%s: Unknown command %d (arguments %d, %d)",
__FUNCTION__, cmd, arg1, arg2);
@@ -1712,27 +1677,6 @@
}
}
-status_t Camera2Client::commandSetVideoBufferCountL(size_t count) {
- if (recordingEnabledL()) {
- ALOGE("%s: Camera %d: Error setting video buffer count after "
- "recording was started", __FUNCTION__, mCameraId);
- return INVALID_OPERATION;
- }
-
- return mStreamingProcessor->setRecordingBufferCount(count);
-}
-
-status_t Camera2Client::commandSetVideoFormatL(int format,
- android_dataspace dataspace) {
- if (recordingEnabledL()) {
- ALOGE("%s: Camera %d: Error setting video format after "
- "recording was started", __FUNCTION__, mCameraId);
- return INVALID_OPERATION;
- }
-
- return mStreamingProcessor->setRecordingFormat(format, dataspace);
-}
-
void Camera2Client::notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras) {
int32_t err = CAMERA_ERROR_UNKNOWN;
@@ -2156,6 +2100,84 @@
return res;
}
+status_t Camera2Client::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) {
+ ATRACE_CALL();
+ ALOGV("%s: E", __FUNCTION__);
+ Mutex::Autolock icl(mBinderSerializationLock);
+ status_t res;
+ if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+ sp<IBinder> binder = IInterface::asBinder(bufferProducer);
+ if (binder == mVideoSurface) {
+ ALOGV("%s: Camera %d: New video window is same as old video window",
+ __FUNCTION__, mCameraId);
+ return NO_ERROR;
+ }
+
+ sp<Surface> window;
+ int format;
+ android_dataspace dataSpace;
+
+ if (bufferProducer != nullptr) {
+ // Using controlledByApp flag to ensure that the buffer queue remains in
+ // async mode for the old camera API, where many applications depend
+ // on that behavior.
+ window = new Surface(bufferProducer, /*controlledByApp*/ true);
+
+ ANativeWindow *anw = window.get();
+
+ if ((res = anw->query(anw, NATIVE_WINDOW_FORMAT, &format)) != OK) {
+ ALOGE("%s: Failed to query Surface format", __FUNCTION__);
+ return res;
+ }
+
+ if ((res = anw->query(anw, NATIVE_WINDOW_DEFAULT_DATASPACE,
+ reinterpret_cast<int*>(&dataSpace))) != OK) {
+ ALOGE("%s: Failed to query Surface dataSpace", __FUNCTION__);
+ return res;
+ }
+ }
+
+ Parameters::State state;
+ {
+ SharedParameters::Lock l(mParameters);
+ state = l.mParameters.state;
+ }
+
+ switch (state) {
+ case Parameters::STOPPED:
+ case Parameters::WAITING_FOR_PREVIEW_WINDOW:
+ case Parameters::PREVIEW:
+ // OK
+ break;
+ case Parameters::DISCONNECTED:
+ case Parameters::RECORD:
+ case Parameters::STILL_CAPTURE:
+ case Parameters::VIDEO_SNAPSHOT:
+ default:
+ ALOGE("%s: Camera %d: Cannot set video target while in state %s",
+ __FUNCTION__, mCameraId,
+ Parameters::getStateName(state));
+ return INVALID_OPERATION;
+ }
+
+ mVideoSurface = binder;
+ res = mStreamingProcessor->setRecordingWindow(window);
+ if (res != OK) {
+ ALOGE("%s: Unable to set new recording window: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ {
+ SharedParameters::Lock l(mParameters);
+ l.mParameters.videoFormat = format;
+ l.mParameters.videoDataSpace = dataSpace;
+ }
+
+ return OK;
+}
+
const char* Camera2Client::kAutofocusLabel = "autofocus";
const char* Camera2Client::kTakepictureLabel = "take_picture";
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index d50bf63..428dca1 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -24,7 +24,7 @@
#include "api1/client2/FrameProcessor.h"
//#include "api1/client2/StreamingProcessor.h"
//#include "api1/client2/JpegProcessor.h"
-//#include "api1/client2/ZslProcessorInterface.h"
+//#include "api1/client2/ZslProcessor.h"
//#include "api1/client2/CaptureSequencer.h"
//#include "api1/client2/CallbackProcessor.h"
@@ -34,7 +34,7 @@
class StreamingProcessor;
class JpegProcessor;
-class ZslProcessorInterface;
+class ZslProcessor;
class CaptureSequencer;
class CallbackProcessor;
@@ -43,7 +43,7 @@
class IMemory;
/**
* Interface between android.hardware.Camera API and Camera HAL device for versions
- * CAMERA_DEVICE_API_VERSION_2_0 and 3_0.
+ * CAMERA_DEVICE_API_VERSION_3_0 and above.
*/
class Camera2Client :
public Camera2ClientBase<CameraService::Client>
@@ -66,7 +66,7 @@
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual status_t storeMetaDataInBuffers(bool enabled);
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode);
virtual status_t startRecording();
virtual void stopRecording();
virtual bool recordingEnabled();
@@ -79,6 +79,7 @@
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode,
const CaptureResultExtras& resultExtras);
+ virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
/**
* Interface used by CameraService
@@ -194,6 +195,7 @@
/* Preview/Recording related members */
sp<IBinder> mPreviewSurface;
+ sp<IBinder> mVideoSurface;
sp<camera2::StreamingProcessor> mStreamingProcessor;
/** Preview callback related members */
@@ -204,12 +206,7 @@
sp<camera2::CaptureSequencer> mCaptureSequencer;
sp<camera2::JpegProcessor> mJpegProcessor;
- sp<camera2::ZslProcessorInterface> mZslProcessor;
- sp<Thread> mZslProcessorThread;
-
- /** Notification-related members */
-
- bool mAfInMotion;
+ sp<camera2::ZslProcessor> mZslProcessor;
/** Utility members */
bool mLegacyMode;
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index 4153658..0eeb1c6 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -477,14 +477,24 @@
mHardware->releaseRecordingFrame(mem);
}
-status_t CameraClient::storeMetaDataInBuffers(bool enabled)
-{
- LOG1("storeMetaDataInBuffers: %s", enabled? "true": "false");
+status_t CameraClient::setVideoBufferMode(int32_t videoBufferMode) {
+ LOG1("setVideoBufferMode: %d", videoBufferMode);
+ bool enableMetadataInBuffers = false;
+
+ if (videoBufferMode == VIDEO_BUFFER_MODE_DATA_CALLBACK_METADATA) {
+ enableMetadataInBuffers = true;
+ } else if (videoBufferMode != VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV) {
+ ALOGE("%s: %d: videoBufferMode %d is not supported.", __FUNCTION__, __LINE__,
+ videoBufferMode);
+ return BAD_VALUE;
+ }
+
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) {
return UNKNOWN_ERROR;
}
- return mHardware->storeMetaDataInBuffers(enabled);
+
+ return mHardware->storeMetaDataInBuffers(enableMetadataInBuffers);
}
bool CameraClient::previewEnabled() {
@@ -986,4 +996,9 @@
return -1;
}
+status_t CameraClient::setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer) {
+ ALOGE("%s: %d: CameraClient doesn't support setting a video target.", __FUNCTION__, __LINE__);
+ return INVALID_OPERATION;
+}
+
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 95616b2..66e57d5 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -44,7 +44,7 @@
virtual status_t startPreview();
virtual void stopPreview();
virtual bool previewEnabled();
- virtual status_t storeMetaDataInBuffers(bool enabled);
+ virtual status_t setVideoBufferMode(int32_t videoBufferMode);
virtual status_t startRecording();
virtual void stopRecording();
virtual bool recordingEnabled();
@@ -55,6 +55,7 @@
virtual status_t setParameters(const String8& params);
virtual String8 getParameters() const;
virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2);
+ virtual status_t setVideoTarget(const sp<IGraphicBufferProducer>& bufferProducer);
// Interface used by CameraService
CameraClient(const sp<CameraService>& cameraService,
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp b/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
deleted file mode 100644
index 5502dcb..0000000
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.cpp
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "Camera2-BurstCapture"
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-
-#include "BurstCapture.h"
-
-#include "api1/Camera2Client.h"
-#include "api1/client2/JpegCompressor.h"
-
-namespace android {
-namespace camera2 {
-
-BurstCapture::BurstCapture(wp<Camera2Client> client, wp<CaptureSequencer> sequencer):
- mCaptureStreamId(NO_STREAM),
- mClient(client),
- mSequencer(sequencer)
-{
-}
-
-BurstCapture::~BurstCapture() {
-}
-
-status_t BurstCapture::start(Vector<CameraMetadata> &/*metadatas*/,
- int32_t /*firstCaptureId*/) {
- ALOGE("Not completely implemented");
- return INVALID_OPERATION;
-}
-
-void BurstCapture::onFrameAvailable(const BufferItem &/*item*/) {
- ALOGV("%s", __FUNCTION__);
- Mutex::Autolock l(mInputMutex);
- if(!mInputChanged) {
- mInputChanged = true;
- mInputSignal.signal();
- }
-}
-
-bool BurstCapture::threadLoop() {
- status_t res;
- {
- Mutex::Autolock l(mInputMutex);
- while(!mInputChanged) {
- res = mInputSignal.waitRelative(mInputMutex, kWaitDuration);
- if(res == TIMED_OUT) return true;
- }
- mInputChanged = false;
- }
-
- do {
- sp<Camera2Client> client = mClient.promote();
- if(client == 0) return false;
- ALOGV("%s: Calling processFrameAvailable()", __FUNCTION__);
- res = processFrameAvailable(client);
- } while(res == OK);
-
- return true;
-}
-
-CpuConsumer::LockedBuffer* BurstCapture::jpegEncode(
- CpuConsumer::LockedBuffer *imgBuffer,
- int /*quality*/)
-{
- ALOGV("%s", __FUNCTION__);
-
- CpuConsumer::LockedBuffer *imgEncoded = new CpuConsumer::LockedBuffer;
- uint8_t *data = new uint8_t[ANDROID_JPEG_MAX_SIZE];
- imgEncoded->data = data;
- imgEncoded->width = imgBuffer->width;
- imgEncoded->height = imgBuffer->height;
- imgEncoded->stride = imgBuffer->stride;
-
- Vector<CpuConsumer::LockedBuffer*> buffers;
- buffers.push_back(imgBuffer);
- buffers.push_back(imgEncoded);
-
- sp<JpegCompressor> jpeg = new JpegCompressor();
- jpeg->start(buffers, 1);
-
- bool success = jpeg->waitForDone(10 * 1e9);
- if(success) {
- return buffers[1];
- }
- else {
- ALOGE("%s: JPEG encode timed out", __FUNCTION__);
- return NULL; // TODO: maybe change function return value to status_t
- }
-}
-
-status_t BurstCapture::processFrameAvailable(sp<Camera2Client> &/*client*/) {
- ALOGE("Not implemented");
- return INVALID_OPERATION;
-}
-
-} // namespace camera2
-} // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/BurstCapture.h b/services/camera/libcameraservice/api1/client2/BurstCapture.h
deleted file mode 100644
index c3b7722..0000000
--- a/services/camera/libcameraservice/api1/client2/BurstCapture.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_BURST_CAPTURE_H
-#define ANDROID_SERVERS_CAMERA_BURST_CAPTURE_H
-
-#include <camera/CameraMetadata.h>
-#include <binder/MemoryBase.h>
-#include <binder/MemoryHeapBase.h>
-#include <gui/CpuConsumer.h>
-
-#include "device2/Camera2Device.h"
-
-namespace android {
-
-class Camera2Client;
-
-namespace camera2 {
-
-class CaptureSequencer;
-
-class BurstCapture : public virtual Thread,
- public virtual CpuConsumer::FrameAvailableListener
-{
-public:
- BurstCapture(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
- virtual ~BurstCapture();
-
- virtual void onFrameAvailable(const BufferItem& item);
- virtual status_t start(Vector<CameraMetadata> &metadatas, int32_t firstCaptureId);
-
-protected:
- Mutex mInputMutex;
- bool mInputChanged;
- Condition mInputSignal;
- int mCaptureStreamId;
- wp<Camera2Client> mClient;
- wp<CaptureSequencer> mSequencer;
-
- // Should only be accessed by processing thread
- enum {
- NO_STREAM = -1
- };
-
- CpuConsumer::LockedBuffer* jpegEncode(
- CpuConsumer::LockedBuffer *imgBuffer,
- int quality);
-
- virtual status_t processFrameAvailable(sp<Camera2Client> &client);
-
-private:
- virtual bool threadLoop();
- static const nsecs_t kWaitDuration = 10000000; // 10 ms
-};
-
-} // namespace camera2
-} // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
index a290536..a22442f 100644
--- a/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/CallbackProcessor.h
@@ -33,7 +33,7 @@
namespace camera2 {
-class Parameters;
+struct Parameters;
/***
* Still image capture output image processing
@@ -75,7 +75,6 @@
sp<CpuConsumer> mCallbackConsumer;
sp<Surface> mCallbackWindow;
sp<Camera2Heap> mCallbackHeap;
- int mCallbackHeapId;
size_t mCallbackHeapHead, mCallbackHeapFree;
virtual bool threadLoop();
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 5f7fd74..61e1442 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -26,9 +26,8 @@
#include "api1/Camera2Client.h"
#include "api1/client2/CaptureSequencer.h"
-#include "api1/client2/BurstCapture.h"
#include "api1/client2/Parameters.h"
-#include "api1/client2/ZslProcessorInterface.h"
+#include "api1/client2/ZslProcessor.h"
namespace android {
namespace camera2 {
@@ -59,7 +58,7 @@
ALOGV("%s: Exit", __FUNCTION__);
}
-void CaptureSequencer::setZslProcessor(wp<ZslProcessorInterface> processor) {
+void CaptureSequencer::setZslProcessor(wp<ZslProcessor> processor) {
Mutex::Autolock l(mInputMutex);
mZslProcessor = processor;
}
@@ -111,6 +110,7 @@
void CaptureSequencer::notifyShutter(const CaptureResultExtras& resultExtras,
nsecs_t timestamp) {
ATRACE_CALL();
+ (void) timestamp;
Mutex::Autolock l(mInputMutex);
if (!mHalNotifiedShutter && resultExtras.requestId == mShutterCaptureId) {
mHalNotifiedShutter = true;
@@ -174,8 +174,6 @@
"STANDARD_PRECAPTURE_WAIT",
"STANDARD_CAPTURE",
"STANDARD_CAPTURE_WAIT",
- "BURST_CAPTURE_START",
- "BURST_CAPTURE_WAIT",
"DONE",
"ERROR",
"UNKNOWN"
@@ -192,8 +190,6 @@
&CaptureSequencer::manageStandardPrecaptureWait,
&CaptureSequencer::manageStandardCapture,
&CaptureSequencer::manageStandardCaptureWait,
- &CaptureSequencer::manageBurstCaptureStart,
- &CaptureSequencer::manageBurstCaptureWait,
&CaptureSequencer::manageDone,
};
@@ -293,7 +289,7 @@
}
takePictureCounter = l.mParameters.takePictureCounter;
}
- sp<ZslProcessorInterface> processor = mZslProcessor.promote();
+ sp<ZslProcessor> processor = mZslProcessor.promote();
if (processor != 0) {
ALOGV("%s: Memory optimization, clearing ZSL queue",
__FUNCTION__);
@@ -336,10 +332,6 @@
return DONE;
}
- if(l.mParameters.lightFx != Parameters::LIGHTFX_NONE &&
- l.mParameters.state == Parameters::STILL_CAPTURE) {
- nextState = BURST_CAPTURE_START;
- }
else if (l.mParameters.zslMode &&
l.mParameters.state == Parameters::STILL_CAPTURE &&
l.mParameters.flashMode != Parameters::FLASH_MODE_ON) {
@@ -361,7 +353,7 @@
sp<Camera2Client> &client) {
ALOGV("%s", __FUNCTION__);
status_t res;
- sp<ZslProcessorInterface> processor = mZslProcessor.promote();
+ sp<ZslProcessor> processor = mZslProcessor.promote();
if (processor == 0) {
ALOGE("%s: No ZSL queue to use!", __FUNCTION__);
return DONE;
@@ -664,76 +656,6 @@
return STANDARD_CAPTURE_WAIT;
}
-CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureStart(
- sp<Camera2Client> &client) {
- ALOGV("%s", __FUNCTION__);
- status_t res;
- ATRACE_CALL();
-
- // check which burst mode is set, create respective burst object
- {
- SharedParameters::Lock l(client->getParameters());
-
- res = updateCaptureRequest(l.mParameters, client);
- if(res != OK) {
- return DONE;
- }
-
- //
- // check for burst mode type in mParameters here
- //
- mBurstCapture = new BurstCapture(client, this);
- }
-
- res = mCaptureRequest.update(ANDROID_REQUEST_ID, &mCaptureId, 1);
- if (res == OK) {
- res = mCaptureRequest.sort();
- }
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to set up still capture request: %s (%d)",
- __FUNCTION__, client->getCameraId(), strerror(-res), res);
- return DONE;
- }
-
- CameraMetadata captureCopy = mCaptureRequest;
- if (captureCopy.entryCount() == 0) {
- ALOGE("%s: Camera %d: Unable to copy capture request for HAL device",
- __FUNCTION__, client->getCameraId());
- return DONE;
- }
-
- Vector<CameraMetadata> requests;
- requests.push(mCaptureRequest);
- res = mBurstCapture->start(requests, mCaptureId);
- mTimeoutCount = kMaxTimeoutsForCaptureEnd * 10;
- return BURST_CAPTURE_WAIT;
-}
-
-CaptureSequencer::CaptureState CaptureSequencer::manageBurstCaptureWait(
- sp<Camera2Client> &/*client*/) {
- status_t res;
- ATRACE_CALL();
- while (!mNewCaptureReceived) {
- res = mNewCaptureSignal.waitRelative(mInputMutex, kWaitDuration);
- if (res == TIMED_OUT) {
- mTimeoutCount--;
- break;
- }
- }
-
- if (mTimeoutCount <= 0) {
- ALOGW("Timed out waiting for burst capture to complete");
- return DONE;
- }
- if (mNewCaptureReceived) {
- mNewCaptureReceived = false;
- // TODO: update mCaptureId to last burst's capture ID + 1?
- return DONE;
- }
-
- return BURST_CAPTURE_WAIT;
-}
-
status_t CaptureSequencer::updateCaptureRequest(const Parameters ¶ms,
sp<Camera2Client> &client) {
ATRACE_CALL();
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index 10252fb..b05207e 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -34,8 +34,7 @@
namespace camera2 {
-class ZslProcessorInterface;
-class BurstCapture;
+class ZslProcessor;
/**
* Manages the still image capture process for
@@ -49,7 +48,7 @@
~CaptureSequencer();
// Get reference to the ZslProcessor, which holds the ZSL buffers and frames
- void setZslProcessor(wp<ZslProcessorInterface> processor);
+ void setZslProcessor(wp<ZslProcessor> processor);
// Begin still image capture
status_t startCapture(int msgType);
@@ -113,8 +112,7 @@
static const int kMaxTimeoutsForCaptureEnd = 40; // 4 sec
wp<Camera2Client> mClient;
- wp<ZslProcessorInterface> mZslProcessor;
- sp<BurstCapture> mBurstCapture;
+ wp<ZslProcessor> mZslProcessor;
enum CaptureState {
IDLE,
@@ -126,8 +124,6 @@
STANDARD_PRECAPTURE_WAIT,
STANDARD_CAPTURE,
STANDARD_CAPTURE_WAIT,
- BURST_CAPTURE_START,
- BURST_CAPTURE_WAIT,
DONE,
ERROR,
NUM_CAPTURE_STATES
@@ -165,9 +161,6 @@
CaptureState manageStandardCapture(sp<Camera2Client> &client);
CaptureState manageStandardCaptureWait(sp<Camera2Client> &client);
- CaptureState manageBurstCaptureStart(sp<Camera2Client> &client);
- CaptureState manageBurstCaptureWait(sp<Camera2Client> &client);
-
CaptureState manageDone(sp<Camera2Client> &client);
// Utility methods
diff --git a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
index 40d53b3..6490682 100644
--- a/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/FrameProcessor.cpp
@@ -170,7 +170,7 @@
entry = frame.find(ANDROID_SCALER_CROP_REGION);
if (entry.count < 4) {
- ALOGE("%s: Camera %d: Unable to read crop region (count = %d)",
+ ALOGE("%s: Camera %d: Unable to read crop region (count = %zu)",
__FUNCTION__, client->getCameraId(), entry.count);
return res;
}
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
index bd9786f..3923853 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.cpp
@@ -108,7 +108,7 @@
return NO_MEMORY;
}
}
- ALOGV("%s: Camera %d: JPEG capture heap now %d bytes; requested %d bytes",
+ ALOGV("%s: Camera %d: JPEG capture heap now %zu bytes; requested %zd bytes",
__FUNCTION__, mId, mCaptureHeap->getSize(), maxJpegSize);
if (mCaptureStreamId != NO_STREAM) {
diff --git a/services/camera/libcameraservice/api1/client2/JpegProcessor.h b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
index fbdae11..ac6f5c7 100644
--- a/services/camera/libcameraservice/api1/client2/JpegProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/JpegProcessor.h
@@ -35,7 +35,7 @@
namespace camera2 {
class CaptureSequencer;
-class Parameters;
+struct Parameters;
/***
* Still image capture output image processing
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp
index fc5ebac..7a97396 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.cpp
+++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp
@@ -30,6 +30,7 @@
#include "Parameters.h"
#include "system/camera.h"
#include "hardware/camera_common.h"
+#include <camera/ICamera.h>
#include <media/MediaProfiles.h>
#include <media/mediarecorder.h>
@@ -870,8 +871,9 @@
}
// Set up initial state for non-Camera.Parameters state variables
-
- storeMetadataInBuffers = true;
+ videoFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ videoDataSpace = HAL_DATASPACE_BT709;
+ videoBufferMode = ICamera::VIDEO_BUFFER_MODE_DATA_CALLBACK_YUV;
playShutterSound = true;
enableFaceDetect = false;
@@ -913,8 +915,6 @@
ALOGI("%s: zslMode: %d slowJpegMode %d", __FUNCTION__, zslMode, slowJpegMode);
- lightFx = LIGHTFX_NONE;
-
state = STOPPED;
paramsFlattened = params.flatten();
@@ -1864,10 +1864,6 @@
ALOGE("%s: Video stabilization not supported", __FUNCTION__);
}
- // LIGHTFX
- validatedParams.lightFx = lightFxStringToEnum(
- newParams.get(CameraParameters::KEY_LIGHTFX));
-
/** Update internal parameters */
*this = validatedParams;
@@ -1959,7 +1955,7 @@
if (res != OK) return res;
// android.hardware.Camera requires that when face detect is enabled, the
- // camera is in a face-priority mode. HAL2 splits this into separate parts
+ // camera is in a face-priority mode. HAL3.x splits this into separate parts
// (face detection statistics and face priority scene mode). Map from other
// to the other.
bool sceneModeActive =
@@ -2501,18 +2497,6 @@
}
}
-Parameters::Parameters::lightFxMode_t Parameters::lightFxStringToEnum(
- const char *lightFxMode) {
- return
- !lightFxMode ?
- Parameters::LIGHTFX_NONE :
- !strcmp(lightFxMode, CameraParameters::LIGHTFX_LOWLIGHT) ?
- Parameters::LIGHTFX_LOWLIGHT :
- !strcmp(lightFxMode, CameraParameters::LIGHTFX_HDR) ?
- Parameters::LIGHTFX_HDR :
- Parameters::LIGHTFX_NONE;
-}
-
status_t Parameters::parseAreas(const char *areasCStr,
Vector<Parameters::Area> *areas) {
static const size_t NUM_FIELDS = 5;
diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h
index 972d007..c437722 100644
--- a/services/camera/libcameraservice/api1/client2/Parameters.h
+++ b/services/camera/libcameraservice/api1/client2/Parameters.h
@@ -131,23 +131,19 @@
int zoom;
- int videoWidth, videoHeight;
+ int videoWidth, videoHeight, videoFormat;
+ android_dataspace videoDataSpace;
bool recordingHint;
bool videoStabilization;
- enum lightFxMode_t {
- LIGHTFX_NONE = 0,
- LIGHTFX_LOWLIGHT,
- LIGHTFX_HDR
- } lightFx;
-
CameraParameters2 params;
String8 paramsFlattened;
// These parameters are also part of the camera API-visible state, but not
// directly listed in Camera.Parameters
- bool storeMetadataInBuffers;
+ // One of ICamera::VIDEO_BUFFER_MODE_*
+ int32_t videoBufferMode;
bool playShutterSound;
bool enableFaceDetect;
@@ -307,7 +303,6 @@
static const char* flashModeEnumToString(flashMode_t flashMode);
static focusMode_t focusModeStringToEnum(const char *focusMode);
static const char* focusModeEnumToString(focusMode_t focusMode);
- static lightFxMode_t lightFxStringToEnum(const char *lightFxMode);
static status_t parseAreas(const char *areasCStr,
Vector<Area> *areas);
@@ -330,7 +325,7 @@
static const int kFpsToApiScale = 1000;
// Transform from (-1000,-1000)-(1000,1000) normalized coords from camera
- // API to HAL2 (0,0)-(activePixelArray.width/height) coordinates
+ // API to HAL3 (0,0)-(activePixelArray.width/height) coordinates
int normalizedXToArray(int x) const;
int normalizedYToArray(int y) const;
@@ -350,7 +345,7 @@
private:
// Convert from viewfinder crop-region relative array coordinates
- // to HAL2 sensor array coordinates
+ // to HAL3 sensor array coordinates
int cropXToArray(int x) const;
int cropYToArray(int y) const;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index 66d7b00..211bdae 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -49,13 +49,7 @@
mPreviewRequestId(Camera2Client::kPreviewRequestIdStart),
mPreviewStreamId(NO_STREAM),
mRecordingRequestId(Camera2Client::kRecordingRequestIdStart),
- mRecordingStreamId(NO_STREAM),
- mRecordingFrameAvailable(false),
- mRecordingHeapCount(kDefaultRecordingHeapCount),
- mRecordingHeapFree(kDefaultRecordingHeapCount),
- mRecordingFormat(kDefaultRecordingFormat),
- mRecordingDataSpace(kDefaultRecordingDataSpace),
- mRecordingGrallocUsage(kDefaultRecordingGrallocUsage)
+ mRecordingStreamId(NO_STREAM)
{
}
@@ -78,11 +72,30 @@
return OK;
}
+status_t StreamingProcessor::setRecordingWindow(sp<Surface> window) {
+ ATRACE_CALL();
+ status_t res;
+
+ res = deleteRecordingStream();
+ if (res != OK) return res;
+
+ Mutex::Autolock m(mMutex);
+
+ mRecordingWindow = window;
+
+ return OK;
+}
+
bool StreamingProcessor::haveValidPreviewWindow() const {
Mutex::Autolock m(mMutex);
return mPreviewWindow != 0;
}
+bool StreamingProcessor::haveValidRecordingWindow() const {
+ Mutex::Autolock m(mMutex);
+ return mRecordingWindow != nullptr;
+}
+
status_t StreamingProcessor::updatePreviewRequest(const Parameters ¶ms) {
ATRACE_CALL();
status_t res;
@@ -244,86 +257,6 @@
return mPreviewStreamId;
}
-status_t StreamingProcessor::setRecordingBufferCount(size_t count) {
- ATRACE_CALL();
- // Make sure we can support this many buffer slots
- if (count > BufferQueue::NUM_BUFFER_SLOTS) {
- ALOGE("%s: Camera %d: Too many recording buffers requested: %zu, max %d",
- __FUNCTION__, mId, count, BufferQueue::NUM_BUFFER_SLOTS);
- return BAD_VALUE;
- }
-
- Mutex::Autolock m(mMutex);
-
- ALOGV("%s: Camera %d: New recording buffer count from encoder: %zu",
- __FUNCTION__, mId, count);
-
- // Need to re-size consumer and heap
- if (mRecordingHeapCount != count) {
- ALOGV("%s: Camera %d: Resetting recording heap and consumer",
- __FUNCTION__, mId);
-
- if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) {
- ALOGE("%s: Camera %d: Setting recording buffer count when "
- "recording stream is already active!", __FUNCTION__,
- mId);
- return INVALID_OPERATION;
- }
-
- releaseAllRecordingFramesLocked();
-
- if (mRecordingHeap != 0) {
- mRecordingHeap.clear();
- }
- mRecordingHeapCount = count;
- mRecordingHeapFree = count;
-
- mRecordingConsumer.clear();
- }
-
- return OK;
-}
-
-status_t StreamingProcessor::setRecordingFormat(int format,
- android_dataspace dataSpace) {
- ATRACE_CALL();
-
- Mutex::Autolock m(mMutex);
-
- ALOGV("%s: Camera %d: New recording format/dataspace from encoder: %X, %X",
- __FUNCTION__, mId, format, dataSpace);
-
- mRecordingFormat = format;
- mRecordingDataSpace = dataSpace;
- int prevGrallocUsage = mRecordingGrallocUsage;
- if (mRecordingFormat == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
- mRecordingGrallocUsage = GRALLOC_USAGE_HW_VIDEO_ENCODER;
- } else {
- mRecordingGrallocUsage = GRALLOC_USAGE_SW_READ_OFTEN;
- }
-
- ALOGV("%s: Camera %d: New recording gralloc usage: %08X", __FUNCTION__, mId,
- mRecordingGrallocUsage);
-
- if (prevGrallocUsage != mRecordingGrallocUsage) {
- ALOGV("%s: Camera %d: Resetting recording consumer for new usage",
- __FUNCTION__, mId);
-
- if (isStreamActive(mActiveStreamIds, mRecordingStreamId)) {
- ALOGE("%s: Camera %d: Changing recording format when "
- "recording stream is already active!", __FUNCTION__,
- mId);
- return INVALID_OPERATION;
- }
-
- releaseAllRecordingFramesLocked();
-
- mRecordingConsumer.clear();
- }
-
- return OK;
-}
-
status_t StreamingProcessor::updateRecordingRequest(const Parameters ¶ms) {
ATRACE_CALL();
status_t res;
@@ -395,11 +328,11 @@
return res;
}
- if (mRecordingConsumer == 0 ||
+ if (mRecordingWindow == nullptr ||
currentWidth != (uint32_t)params.videoWidth ||
currentHeight != (uint32_t)params.videoHeight ||
- currentFormat != (uint32_t)mRecordingFormat ||
- currentDataSpace != mRecordingDataSpace) {
+ currentFormat != (uint32_t)params.videoFormat ||
+ currentDataSpace != params.videoDataSpace) {
*needsUpdate = true;
}
*needsUpdate = false;
@@ -417,26 +350,6 @@
return INVALID_OPERATION;
}
- bool newConsumer = false;
- if (mRecordingConsumer == 0) {
- ALOGV("%s: Camera %d: Creating recording consumer with %zu + 1 "
- "consumer-side buffers", __FUNCTION__, mId, mRecordingHeapCount);
- // Create CPU buffer queue endpoint. We need one more buffer here so that we can
- // always acquire and free a buffer when the heap is full; otherwise the consumer
- // will have buffers in flight we'll never clear out.
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- mRecordingConsumer = new BufferItemConsumer(consumer,
- mRecordingGrallocUsage,
- mRecordingHeapCount + 1);
- mRecordingConsumer->setFrameAvailableListener(this);
- mRecordingConsumer->setName(String8("Camera2-RecordingConsumer"));
- mRecordingWindow = new Surface(producer);
- newConsumer = true;
- // Allocate memory later, since we don't know buffer size until receipt
- }
-
if (mRecordingStreamId != NO_STREAM) {
// Check if stream parameters have to change
uint32_t currentWidth, currentHeight;
@@ -453,9 +366,8 @@
}
if (currentWidth != (uint32_t)params.videoWidth ||
currentHeight != (uint32_t)params.videoHeight ||
- currentFormat != (uint32_t)mRecordingFormat ||
- currentDataSpace != mRecordingDataSpace ||
- newConsumer) {
+ currentFormat != (uint32_t)params.videoFormat ||
+ currentDataSpace != params.videoDataSpace) {
// TODO: Should wait to be sure previous recording has finished
res = device->deleteStream(mRecordingStreamId);
@@ -475,10 +387,9 @@
}
if (mRecordingStreamId == NO_STREAM) {
- mRecordingFrameCount = 0;
res = device->createStream(mRecordingWindow,
params.videoWidth, params.videoHeight,
- mRecordingFormat, mRecordingDataSpace,
+ params.videoFormat, params.videoDataSpace,
CAMERA3_STREAM_ROTATION_0, &mRecordingStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Can't create output stream for recording: "
@@ -542,20 +453,6 @@
Mutex::Autolock m(mMutex);
- // If a recording stream is being started up and no recording
- // stream is active yet, free up any outstanding buffers left
- // from the previous recording session. There should never be
- // any, so if there are, warn about it.
- bool isRecordingStreamIdle = !isStreamActive(mActiveStreamIds, mRecordingStreamId);
- bool startRecordingStream = isStreamActive(outputStreams, mRecordingStreamId);
- if (startRecordingStream && isRecordingStreamIdle) {
- releaseAllRecordingFramesLocked();
- }
-
- ALOGV("%s: Camera %d: %s started, recording heap has %zu free of %zu",
- __FUNCTION__, mId, (type == PREVIEW) ? "preview" : "recording",
- mRecordingHeapFree, mRecordingHeapCount);
-
CameraMetadata &request = (type == PREVIEW) ?
mPreviewRequest : mRecordingRequest;
@@ -692,272 +589,6 @@
return OK;
}
-void StreamingProcessor::onFrameAvailable(const BufferItem& /*item*/) {
- ATRACE_CALL();
- Mutex::Autolock l(mMutex);
- if (!mRecordingFrameAvailable) {
- mRecordingFrameAvailable = true;
- mRecordingFrameAvailableSignal.signal();
- }
-
-}
-
-bool StreamingProcessor::threadLoop() {
- status_t res;
-
- {
- Mutex::Autolock l(mMutex);
- while (!mRecordingFrameAvailable) {
- res = mRecordingFrameAvailableSignal.waitRelative(
- mMutex, kWaitDuration);
- if (res == TIMED_OUT) return true;
- }
- mRecordingFrameAvailable = false;
- }
-
- do {
- res = processRecordingFrame();
- } while (res == OK);
-
- return true;
-}
-
-status_t StreamingProcessor::processRecordingFrame() {
- ATRACE_CALL();
- status_t res;
- sp<Camera2Heap> recordingHeap;
- size_t heapIdx = 0;
- nsecs_t timestamp;
-
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- // Discard frames during shutdown
- BufferItem imgBuffer;
- res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
- if (res != OK) {
- if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
- ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- }
- return res;
- }
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return OK;
- }
-
- {
- /* acquire SharedParameters before mMutex so we don't dead lock
- with Camera2Client code calling into StreamingProcessor */
- SharedParameters::Lock l(client->getParameters());
- Mutex::Autolock m(mMutex);
- BufferItem imgBuffer;
- res = mRecordingConsumer->acquireBuffer(&imgBuffer, 0);
- if (res != OK) {
- if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
- ALOGE("%s: Camera %d: Can't acquire recording buffer: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- }
- return res;
- }
- timestamp = imgBuffer.mTimestamp;
-
- mRecordingFrameCount++;
- ALOGVV("OnRecordingFrame: Frame %d", mRecordingFrameCount);
-
- if (l.mParameters.state != Parameters::RECORD &&
- l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
- ALOGV("%s: Camera %d: Discarding recording image buffers "
- "received after recording done", __FUNCTION__,
- mId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return INVALID_OPERATION;
- }
-
- if (mRecordingHeap == 0) {
- size_t payloadSize = sizeof(VideoNativeMetadata);
- ALOGV("%s: Camera %d: Creating recording heap with %zu buffers of "
- "size %zu bytes", __FUNCTION__, mId,
- mRecordingHeapCount, payloadSize);
-
- mRecordingHeap = new Camera2Heap(payloadSize, mRecordingHeapCount,
- "Camera2Client::RecordingHeap");
- if (mRecordingHeap->mHeap->getSize() == 0) {
- ALOGE("%s: Camera %d: Unable to allocate memory for recording",
- __FUNCTION__, mId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return NO_MEMORY;
- }
- for (size_t i = 0; i < mRecordingBuffers.size(); i++) {
- if (mRecordingBuffers[i].mBuf !=
- BufferItemConsumer::INVALID_BUFFER_SLOT) {
- ALOGE("%s: Camera %d: Non-empty recording buffers list!",
- __FUNCTION__, mId);
- }
- }
- mRecordingBuffers.clear();
- mRecordingBuffers.setCapacity(mRecordingHeapCount);
- mRecordingBuffers.insertAt(0, mRecordingHeapCount);
-
- mRecordingHeapHead = 0;
- mRecordingHeapFree = mRecordingHeapCount;
- }
-
- if (mRecordingHeapFree == 0) {
- ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
- __FUNCTION__, mId);
- mRecordingConsumer->releaseBuffer(imgBuffer);
- return NO_MEMORY;
- }
-
- heapIdx = mRecordingHeapHead;
- mRecordingHeapHead = (mRecordingHeapHead + 1) % mRecordingHeapCount;
- mRecordingHeapFree--;
-
- ALOGVV("%s: Camera %d: Timestamp %lld",
- __FUNCTION__, mId, timestamp);
-
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap =
- mRecordingHeap->mBuffers[heapIdx]->getMemory(&offset,
- &size);
-
- VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
- (uint8_t*)heap->getBase() + offset);
- payload->eType = kMetadataBufferTypeANWBuffer;
- payload->pBuffer = imgBuffer.mGraphicBuffer->getNativeBuffer();
- payload->nFenceFd = -1;
-
- ALOGVV("%s: Camera %d: Sending out ANWBuffer %p",
- __FUNCTION__, mId, payload->pBuffer);
-
- mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
- recordingHeap = mRecordingHeap;
- }
-
- // Call outside locked parameters to allow re-entrancy from notification
- Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks);
- if (l.mRemoteCallback != 0) {
- l.mRemoteCallback->dataCallbackTimestamp(timestamp,
- CAMERA_MSG_VIDEO_FRAME,
- recordingHeap->mBuffers[heapIdx]);
- } else {
- ALOGW("%s: Camera %d: Remote callback gone", __FUNCTION__, mId);
- }
-
- return OK;
-}
-
-void StreamingProcessor::releaseRecordingFrame(const sp<IMemory>& mem) {
- ATRACE_CALL();
- status_t res;
-
- Mutex::Autolock m(mMutex);
- // Make sure this is for the current heap
- ssize_t offset;
- size_t size;
- sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
- if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) {
- ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release "
- "(got %x, expected %x)", __FUNCTION__, mId,
- heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
- return;
- }
-
- VideoNativeMetadata *payload = reinterpret_cast<VideoNativeMetadata*>(
- (uint8_t*)heap->getBase() + offset);
-
- if (payload->eType != kMetadataBufferTypeANWBuffer) {
- ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
- __FUNCTION__, mId, payload->eType,
- kMetadataBufferTypeANWBuffer);
- return;
- }
-
- // Release the buffer back to the recording queue
- size_t itemIndex;
- for (itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
- const BufferItem item = mRecordingBuffers[itemIndex];
- if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT &&
- item.mGraphicBuffer->getNativeBuffer() == payload->pBuffer) {
- break;
- }
- }
-
- if (itemIndex == mRecordingBuffers.size()) {
- ALOGE("%s: Camera %d: Can't find returned ANW Buffer %p in list of "
- "outstanding buffers", __FUNCTION__, mId,
- payload->pBuffer);
- return;
- }
-
- ALOGVV("%s: Camera %d: Freeing returned ANW buffer %p index %d", __FUNCTION__,
- mId, payload->pBuffer, itemIndex);
-
- res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to free recording frame "
- "(Returned ANW buffer: %p): %s (%d)", __FUNCTION__,
- mId, payload->pBuffer, strerror(-res), res);
- return;
- }
- mRecordingBuffers.replaceAt(itemIndex);
-
- mRecordingHeapFree++;
- ALOGV_IF(mRecordingHeapFree == mRecordingHeapCount,
- "%s: Camera %d: All %d recording buffers returned",
- __FUNCTION__, mId, mRecordingHeapCount);
-}
-
-void StreamingProcessor::releaseAllRecordingFramesLocked() {
- ATRACE_CALL();
- status_t res;
-
- if (mRecordingConsumer == 0) {
- return;
- }
-
- ALOGV("%s: Camera %d: Releasing all recording buffers", __FUNCTION__,
- mId);
-
- size_t releasedCount = 0;
- for (size_t itemIndex = 0; itemIndex < mRecordingBuffers.size(); itemIndex++) {
- const BufferItem item = mRecordingBuffers[itemIndex];
- if (item.mBuf != BufferItemConsumer::INVALID_BUFFER_SLOT) {
- res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to free recording frame "
- "(buffer_handle_t: %p): %s (%d)", __FUNCTION__,
- mId, item.mGraphicBuffer->handle, strerror(-res), res);
- }
- mRecordingBuffers.replaceAt(itemIndex);
- releasedCount++;
- }
- }
-
- if (releasedCount > 0) {
- ALOGW("%s: Camera %d: Force-freed %zu outstanding buffers "
- "from previous recording session", __FUNCTION__, mId, releasedCount);
- ALOGE_IF(releasedCount != mRecordingHeapCount - mRecordingHeapFree,
- "%s: Camera %d: Force-freed %zu buffers, but expected %zu",
- __FUNCTION__, mId, releasedCount, mRecordingHeapCount - mRecordingHeapFree);
- }
-
- mRecordingHeapHead = 0;
- mRecordingHeapFree = mRecordingHeapCount;
-}
-
-bool StreamingProcessor::isStreamActive(const Vector<int32_t> &streams,
- int32_t recordingStreamId) {
- for (size_t i = 0; i < streams.size(); i++) {
- if (streams[i] == recordingStreamId) {
- return true;
- }
- }
- return false;
-}
-
-
status_t StreamingProcessor::dump(int fd, const Vector<String16>& /*args*/) {
String8 result;
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
index e0cad3a..57e6389 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.h
@@ -31,30 +31,28 @@
namespace camera2 {
-class Parameters;
+struct Parameters;
class Camera2Heap;
/**
* Management and processing for preview and recording streams
*/
-class StreamingProcessor:
- public Thread, public BufferItemConsumer::FrameAvailableListener {
+class StreamingProcessor : public virtual VirtualLightRefBase {
public:
StreamingProcessor(sp<Camera2Client> client);
~StreamingProcessor();
status_t setPreviewWindow(sp<Surface> window);
+ status_t setRecordingWindow(sp<Surface> window);
bool haveValidPreviewWindow() const;
+ bool haveValidRecordingWindow() const;
status_t updatePreviewRequest(const Parameters ¶ms);
status_t updatePreviewStream(const Parameters ¶ms);
status_t deletePreviewStream();
int getPreviewStreamId() const;
- status_t setRecordingBufferCount(size_t count);
- status_t setRecordingFormat(int format, android_dataspace_t dataspace);
-
status_t updateRecordingRequest(const Parameters ¶ms);
// If needsUpdate is set to true, a updateRecordingStream call with params will recreate
// recording stream
@@ -81,11 +79,6 @@
status_t getActiveRequestId() const;
status_t incrementStreamingIds();
- // Callback for new recording frames from HAL
- virtual void onFrameAvailable(const BufferItem& item);
- // Callback from stagefright which returns used recording frames
- void releaseRecordingFrame(const sp<IMemory>& mem);
-
status_t dump(int fd, const Vector<String16>& args);
private:
@@ -110,47 +103,10 @@
CameraMetadata mPreviewRequest;
sp<Surface> mPreviewWindow;
- // Recording-related members
- static const nsecs_t kWaitDuration = 50000000; // 50 ms
-
int32_t mRecordingRequestId;
int mRecordingStreamId;
- int mRecordingFrameCount;
- sp<BufferItemConsumer> mRecordingConsumer;
sp<Surface> mRecordingWindow;
CameraMetadata mRecordingRequest;
- sp<camera2::Camera2Heap> mRecordingHeap;
-
- bool mRecordingFrameAvailable;
- Condition mRecordingFrameAvailableSignal;
-
- static const size_t kDefaultRecordingHeapCount = 8;
- size_t mRecordingHeapCount;
- Vector<BufferItem> mRecordingBuffers;
- size_t mRecordingHeapHead, mRecordingHeapFree;
-
- static const int kDefaultRecordingFormat =
- HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- int mRecordingFormat;
-
- static const android_dataspace kDefaultRecordingDataSpace =
- HAL_DATASPACE_BT709;
- android_dataspace mRecordingDataSpace;
-
- static const int kDefaultRecordingGrallocUsage =
- GRALLOC_USAGE_HW_VIDEO_ENCODER;
- int mRecordingGrallocUsage;
-
- virtual bool threadLoop();
-
- status_t processRecordingFrame();
-
- // Unilaterally free any buffers still outstanding to stagefright
- void releaseAllRecordingFramesLocked();
-
- // Determine if the specified stream is currently in use
- static bool isStreamActive(const Vector<int32_t> &streams,
- int32_t recordingStreamId);
};
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
index 0b79b31..b127472 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -22,7 +22,7 @@
#ifdef LOG_NNDEBUG
#define ALOGVV(...) ALOGV(__VA_ARGS__)
#else
-#define ALOGVV(...) ((void)0)
+#define ALOGVV(...) if (0) ALOGV(__VA_ARGS__)
#endif
#include <inttypes.h>
@@ -35,6 +35,7 @@
#include "api1/Camera2Client.h"
#include "api1/client2/CaptureSequencer.h"
#include "api1/client2/ZslProcessor.h"
+#include "device3/Camera3Device.h"
namespace android {
namespace camera2 {
@@ -43,35 +44,55 @@
sp<Camera2Client> client,
wp<CaptureSequencer> sequencer):
Thread(false),
+ mLatestClearedBufferTimestamp(0),
mState(RUNNING),
mClient(client),
- mDevice(client->getCameraDevice()),
mSequencer(sequencer),
mId(client->getCameraId()),
- mDeleted(false),
- mZslBufferAvailable(false),
mZslStreamId(NO_STREAM),
- mZslReprocessStreamId(NO_STREAM),
mFrameListHead(0),
- mZslQueueHead(0),
- mZslQueueTail(0) {
- mZslQueue.insertAt(0, kZslBufferDepth);
- mFrameList.insertAt(0, kFrameListDepth);
+ mHasFocuser(false) {
+ // Initialize buffer queue and frame list based on pipeline max depth.
+ size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
+ if (client != 0) {
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
+ if (device != 0) {
+ camera_metadata_ro_entry_t entry =
+ device->info().find(ANDROID_REQUEST_PIPELINE_MAX_DEPTH);
+ if (entry.count == 1) {
+ pipelineMaxDepth = entry.data.u8[0];
+ } else {
+ ALOGW("%s: Unable to find the android.request.pipelineMaxDepth,"
+ " use default pipeline max depth %d", __FUNCTION__,
+ kDefaultMaxPipelineDepth);
+ }
+
+ entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
+ if (entry.count > 0 && entry.data.f[0] != 0.) {
+ mHasFocuser = true;
+ }
+ }
+ }
+
+ ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%zu)",
+ __FUNCTION__, pipelineMaxDepth);
+ // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
+ // earlier than metadata which causes the buffer corresponding to oldest metadata being
+ // removed.
+ mFrameListDepth = pipelineMaxDepth;
+ mBufferQueueDepth = mFrameListDepth + 1;
+
+
+ mZslQueue.insertAt(0, mBufferQueueDepth);
+ mFrameList.insertAt(0, mFrameListDepth);
sp<CaptureSequencer> captureSequencer = mSequencer.promote();
if (captureSequencer != 0) captureSequencer->setZslProcessor(this);
}
ZslProcessor::~ZslProcessor() {
ALOGV("%s: Exit", __FUNCTION__);
- disconnect();
-}
-
-void ZslProcessor::onFrameAvailable(const BufferItem& /*item*/) {
- Mutex::Autolock l(mInputMutex);
- if (!mZslBufferAvailable) {
- mZslBufferAvailable = true;
- mZslBufferAvailableSignal.signal();
- }
+ deleteStream();
}
void ZslProcessor::onResultAvailable(const CaptureResult &result) {
@@ -81,35 +102,27 @@
camera_metadata_ro_entry_t entry;
entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
nsecs_t timestamp = entry.data.i64[0];
- (void)timestamp;
- ALOGVV("Got preview frame for timestamp %" PRId64, timestamp);
+ if (entry.count == 0) {
+ ALOGE("%s: metadata doesn't have timestamp, skip this result", __FUNCTION__);
+ return;
+ }
+
+ entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
+ if (entry.count == 0) {
+ ALOGE("%s: metadata doesn't have frame number, skip this result", __FUNCTION__);
+ return;
+ }
+ int32_t frameNumber = entry.data.i32[0];
+
+ ALOGVV("Got preview metadata for frame %d with timestamp %" PRId64, frameNumber, timestamp);
if (mState != RUNNING) return;
+ // Corresponding buffer has been cleared. No need to push into mFrameList
+ if (timestamp <= mLatestClearedBufferTimestamp) return;
+
mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
- mFrameListHead = (mFrameListHead + 1) % kFrameListDepth;
-
- findMatchesLocked();
-}
-
-void ZslProcessor::onBufferReleased(buffer_handle_t *handle) {
- Mutex::Autolock l(mInputMutex);
-
- // Verify that the buffer is in our queue
- size_t i = 0;
- for (; i < mZslQueue.size(); i++) {
- if (&(mZslQueue[i].buffer.mGraphicBuffer->handle) == handle) break;
- }
- if (i == mZslQueue.size()) {
- ALOGW("%s: Released buffer %p not found in queue",
- __FUNCTION__, handle);
- }
-
- // Erase entire ZSL queue since we've now completed the capture and preview
- // is stopped.
- clearZslQueueLocked();
-
- mState = RUNNING;
+ mFrameListHead = (mFrameListHead + 1) % mFrameListDepth;
}
status_t ZslProcessor::updateStream(const Parameters ¶ms) {
@@ -124,25 +137,13 @@
ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
return INVALID_OPERATION;
}
- sp<CameraDeviceBase> device = mDevice.promote();
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
if (device == 0) {
ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
return INVALID_OPERATION;
}
- if (mZslConsumer == 0) {
- // Create CPU buffer queue endpoint
- sp<IGraphicBufferProducer> producer;
- sp<IGraphicBufferConsumer> consumer;
- BufferQueue::createBufferQueue(&producer, &consumer);
- mZslConsumer = new BufferItemConsumer(consumer,
- GRALLOC_USAGE_HW_CAMERA_ZSL,
- kZslBufferDepth);
- mZslConsumer->setFrameAvailableListener(this);
- mZslConsumer->setName(String8("Camera2-ZslConsumer"));
- mZslWindow = new Surface(producer);
- }
-
if (mZslStreamId != NO_STREAM) {
// Check if stream parameters have to change
uint32_t currentWidth, currentHeight;
@@ -151,57 +152,50 @@
if (res != OK) {
ALOGE("%s: Camera %d: Error querying capture output stream info: "
"%s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
+ client->getCameraId(), strerror(-res), res);
return res;
}
if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
- res = device->deleteReprocessStream(mZslReprocessStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to delete old reprocess stream "
- "for ZSL: %s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
- return res;
- }
- ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
- __FUNCTION__, mId, mZslStreamId);
+ ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
+ "dimensions changed",
+ __FUNCTION__, client->getCameraId(), mZslStreamId);
res = device->deleteStream(mZslStreamId);
- if (res != OK) {
+ if (res == -EBUSY) {
+ ALOGV("%s: Camera %d: Device is busy, call updateStream again "
+ " after it becomes idle", __FUNCTION__, mId);
+ return res;
+ } else if(res != OK) {
ALOGE("%s: Camera %d: Unable to delete old output stream "
"for ZSL: %s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
+ client->getCameraId(), strerror(-res), res);
return res;
}
mZslStreamId = NO_STREAM;
}
}
- mDeleted = false;
-
if (mZslStreamId == NO_STREAM) {
// Create stream for HAL production
// TODO: Sort out better way to select resolution for ZSL
- int streamType = params.quirks.useZslFormat ?
- (int)CAMERA2_HAL_PIXEL_FORMAT_ZSL :
- (int)HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
- res = device->createStream(mZslWindow,
- params.fastInfo.arrayWidth, params.fastInfo.arrayHeight, streamType,
- HAL_DATASPACE_UNKNOWN, CAMERA3_STREAM_ROTATION_0, &mZslStreamId);
+
+ // Note that format specified internally in Camera3ZslStream
+ res = device->createZslStream(
+ params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
+ mBufferQueueDepth,
+ &mZslStreamId,
+ &mZslStream);
if (res != OK) {
- ALOGE("%s: Camera %d: Can't create output stream for ZSL: "
- "%s (%d)", __FUNCTION__, mId,
+ ALOGE("%s: Camera %d: Can't create ZSL stream: "
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
strerror(-res), res);
return res;
}
- res = device->createReprocessStreamFromStream(mZslStreamId,
- &mZslReprocessStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't create reprocess stream for ZSL: "
- "%s (%d)", __FUNCTION__, mId,
- strerror(-res), res);
- return res;
- }
+
+ // Only add the camera3 buffer listener when the stream is created.
+ mZslStream->addBufferListener(this);
}
+
client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
Camera2Client::kPreviewRequestIdEnd,
this,
@@ -212,47 +206,32 @@
status_t ZslProcessor::deleteStream() {
ATRACE_CALL();
- Mutex::Autolock l(mInputMutex);
- // WAR(b/15408128): do not delete stream unless client is being disconnected.
- mDeleted = true;
- return OK;
-}
-
-status_t ZslProcessor::disconnect() {
- ATRACE_CALL();
status_t res;
Mutex::Autolock l(mInputMutex);
if (mZslStreamId != NO_STREAM) {
- sp<CameraDeviceBase> device = mDevice.promote();
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) {
+ ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ sp<Camera3Device> device =
+ reinterpret_cast<Camera3Device*>(client->getCameraDevice().get());
if (device == 0) {
ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
return INVALID_OPERATION;
}
- clearZslQueueLocked();
-
- res = device->deleteReprocessStream(mZslReprocessStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Cannot delete ZSL reprocessing stream %d: "
- "%s (%d)", __FUNCTION__, mId,
- mZslReprocessStreamId, strerror(-res), res);
- return res;
- }
-
- mZslReprocessStreamId = NO_STREAM;
res = device->deleteStream(mZslStreamId);
if (res != OK) {
ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
- "%s (%d)", __FUNCTION__, mId,
+ "%s (%d)", __FUNCTION__, client->getCameraId(),
mZslStreamId, strerror(-res), res);
return res;
}
- mZslWindow.clear();
- mZslConsumer.clear();
-
mZslStreamId = NO_STREAM;
}
return OK;
@@ -263,6 +242,46 @@
return mZslStreamId;
}
+status_t ZslProcessor::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
+ sp<Camera2Client> client = mClient.promote();
+ if (client == 0) {
+ ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+ sp<Camera3Device> device =
+ static_cast<Camera3Device*>(client->getCameraDevice().get());
+ if (device == 0) {
+ ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+ return INVALID_OPERATION;
+ }
+
+ CameraMetadata stillTemplate;
+ device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
+
+ // Find some of the post-processing tags, and assign the value from template to the request.
+ // Only check the aberration mode and noise reduction mode for now, as they are very important
+ // for image quality.
+ uint32_t postProcessingTags[] = {
+ ANDROID_NOISE_REDUCTION_MODE,
+ ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
+ ANDROID_COLOR_CORRECTION_MODE,
+ ANDROID_TONEMAP_MODE,
+ ANDROID_SHADING_MODE,
+ ANDROID_HOT_PIXEL_MODE,
+ ANDROID_EDGE_MODE
+ };
+
+ camera_metadata_entry_t entry;
+ for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
+ entry = stillTemplate.find(postProcessingTags[i]);
+ if (entry.count > 0) {
+ request.update(postProcessingTags[i], entry.data.u8, 1);
+ }
+ }
+
+ return OK;
+}
+
status_t ZslProcessor::pushToReprocess(int32_t requestId) {
ALOGV("%s: Send in reprocess request with id %d",
__FUNCTION__, requestId);
@@ -279,21 +298,30 @@
dumpZslQueue(-1);
}
- if (mZslQueueTail != mZslQueueHead) {
- CameraMetadata request;
- size_t index = mZslQueueTail;
- while (index != mZslQueueHead) {
- if (!mZslQueue[index].frame.isEmpty()) {
- request = mZslQueue[index].frame;
- break;
- }
- index = (index + 1) % kZslBufferDepth;
- }
- if (index == mZslQueueHead) {
- ALOGV("%s: ZSL queue has no valid frames to send yet.",
- __FUNCTION__);
- return NOT_ENOUGH_DATA;
- }
+ size_t metadataIdx;
+ nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
+
+ if (candidateTimestamp == -1) {
+ ALOGE("%s: Could not find good candidate for ZSL reprocessing",
+ __FUNCTION__);
+ return NOT_ENOUGH_DATA;
+ }
+
+ res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
+ /*actualTimestamp*/NULL);
+
+ if (res == mZslStream->NO_BUFFER_AVAILABLE) {
+ ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
+ return NOT_ENOUGH_DATA;
+ } else if (res != OK) {
+ ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
+ __FUNCTION__, strerror(-res), res);
+ return res;
+ }
+
+ {
+ CameraMetadata request = mFrameList[metadataIdx];
+
// Verify that the frame is reasonable for reprocessing
camera_metadata_entry_t entry;
@@ -310,25 +338,51 @@
return NOT_ENOUGH_DATA;
}
- buffer_handle_t *handle =
- &(mZslQueue[index].buffer.mGraphicBuffer->handle);
-
uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
res = request.update(ANDROID_REQUEST_TYPE,
&requestType, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request type",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
int32_t inputStreams[1] =
- { mZslReprocessStreamId };
- if (res == OK) request.update(ANDROID_REQUEST_INPUT_STREAMS,
+ { mZslStreamId };
+ res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
inputStreams, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request input streams",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ uint8_t captureIntent =
+ static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
+ res = request.update(ANDROID_CONTROL_CAPTURE_INTENT,
+ &captureIntent, 1);
+ if (res != OK ) {
+ ALOGE("%s: Unable to update request capture intent",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ // TODO: Shouldn't we also update the latest preview frame?
int32_t outputStreams[1] =
{ client->getCaptureStreamId() };
- if (res == OK) request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
+ res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
outputStreams, 1);
+ if (res != OK) {
+ ALOGE("%s: Unable to update request output streams",
+ __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
res = request.update(ANDROID_REQUEST_ID,
&requestId, 1);
-
if (res != OK ) {
- ALOGE("%s: Unable to update frame to a reprocess request", __FUNCTION__);
+ ALOGE("%s: Unable to update frame to a reprocess request",
+ __FUNCTION__);
return INVALID_OPERATION;
}
@@ -336,17 +390,9 @@
if (res != OK) {
ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
"%s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
+ __FUNCTION__, client->getCameraId(), strerror(-res), res);
return INVALID_OPERATION;
}
- // TODO: have push-and-clear be atomic
- res = client->getCameraDevice()->pushReprocessBuffer(mZslReprocessStreamId,
- handle, this);
- if (res != OK) {
- ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
// Update JPEG settings
{
@@ -355,25 +401,30 @@
if (res != OK) {
ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL "
"capture request: %s (%d)", __FUNCTION__,
- mId,
+ client->getCameraId(),
strerror(-res), res);
return res;
}
}
+ // Update post-processing settings
+ res = updateRequestWithDefaultStillRequest(request);
+ if (res != OK) {
+ ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
+ "may be compromised", __FUNCTION__);
+ }
+
mLatestCapturedRequest = request;
res = client->getCameraDevice()->capture(request);
if (res != OK ) {
- ALOGE("%s: Unable to send ZSL reprocess request to capture: %s (%d)",
- __FUNCTION__, strerror(-res), res);
+ ALOGE("%s: Unable to send ZSL reprocess request to capture: %s"
+ " (%d)", __FUNCTION__, strerror(-res), res);
return res;
}
mState = LOCKED;
- } else {
- ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
- return NOT_ENOUGH_DATA;
}
+
return OK;
}
@@ -386,17 +437,20 @@
}
status_t ZslProcessor::clearZslQueueLocked() {
- for (size_t i = 0; i < mZslQueue.size(); i++) {
- if (mZslQueue[i].buffer.mTimestamp != 0) {
- mZslConsumer->releaseBuffer(mZslQueue[i].buffer);
- }
- mZslQueue.replaceAt(i);
+ if (mZslStream != 0) {
+ // clear result metadata list first.
+ clearZslResultQueueLocked();
+ return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
}
- mZslQueueHead = 0;
- mZslQueueTail = 0;
return OK;
}
+void ZslProcessor::clearZslResultQueueLocked() {
+ mFrameList.clear();
+ mFrameListHead = 0;
+ mFrameList.insertAt(0, mFrameListDepth);
+}
+
void ZslProcessor::dump(int fd, const Vector<String16>& /*args*/) const {
Mutex::Autolock l(mInputMutex);
if (!mLatestCapturedRequest.isEmpty()) {
@@ -411,128 +465,9 @@
}
bool ZslProcessor::threadLoop() {
- status_t res;
-
- {
- Mutex::Autolock l(mInputMutex);
- while (!mZslBufferAvailable) {
- res = mZslBufferAvailableSignal.waitRelative(mInputMutex,
- kWaitDuration);
- if (res == TIMED_OUT) return true;
- }
- mZslBufferAvailable = false;
- }
-
- do {
- res = processNewZslBuffer();
- } while (res == OK);
-
- return true;
-}
-
-status_t ZslProcessor::processNewZslBuffer() {
- ATRACE_CALL();
- status_t res;
- sp<BufferItemConsumer> zslConsumer;
- {
- Mutex::Autolock l(mInputMutex);
- if (mZslConsumer == 0) return OK;
- zslConsumer = mZslConsumer;
- }
- ALOGVV("Trying to get next buffer");
- BufferItem item;
- res = zslConsumer->acquireBuffer(&item, 0);
- if (res != OK) {
- if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
- ALOGE("%s: Camera %d: Error receiving ZSL image buffer: "
- "%s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
- } else {
- ALOGVV(" No buffer");
- }
- return res;
- }
-
- Mutex::Autolock l(mInputMutex);
-
- if (mState == LOCKED) {
- ALOGVV("In capture, discarding new ZSL buffers");
- zslConsumer->releaseBuffer(item);
- return OK;
- }
-
- ALOGVV("Got ZSL buffer: head: %d, tail: %d", mZslQueueHead, mZslQueueTail);
-
- if ( (mZslQueueHead + 1) % kZslBufferDepth == mZslQueueTail) {
- ALOGVV("Releasing oldest buffer");
- zslConsumer->releaseBuffer(mZslQueue[mZslQueueTail].buffer);
- mZslQueue.replaceAt(mZslQueueTail);
- mZslQueueTail = (mZslQueueTail + 1) % kZslBufferDepth;
- }
-
- ZslPair &queueHead = mZslQueue.editItemAt(mZslQueueHead);
-
- queueHead.buffer = item;
- queueHead.frame.release();
-
- mZslQueueHead = (mZslQueueHead + 1) % kZslBufferDepth;
-
- ALOGVV(" Acquired buffer, timestamp %" PRId64, queueHead.buffer.mTimestamp);
-
- findMatchesLocked();
-
- return OK;
-}
-
-void ZslProcessor::findMatchesLocked() {
- ALOGVV("Scanning");
- for (size_t i = 0; i < mZslQueue.size(); i++) {
- ZslPair &queueEntry = mZslQueue.editItemAt(i);
- nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp;
- IF_ALOGV() {
- camera_metadata_entry_t entry;
- nsecs_t frameTimestamp = 0;
- if (!queueEntry.frame.isEmpty()) {
- entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP);
- frameTimestamp = entry.data.i64[0];
- }
- ALOGVV(" %d: b: %" PRId64 "\tf: %" PRId64, i,
- bufferTimestamp, frameTimestamp );
- }
- if (queueEntry.frame.isEmpty() && bufferTimestamp != 0) {
- // Have buffer, no matching frame. Look for one
- for (size_t j = 0; j < mFrameList.size(); j++) {
- bool match = false;
- CameraMetadata &frame = mFrameList.editItemAt(j);
- if (!frame.isEmpty()) {
- camera_metadata_entry_t entry;
- entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
- if (entry.count == 0) {
- ALOGE("%s: Can't find timestamp in frame!",
- __FUNCTION__);
- continue;
- }
- nsecs_t frameTimestamp = entry.data.i64[0];
- if (bufferTimestamp == frameTimestamp) {
- ALOGVV("%s: Found match %" PRId64, __FUNCTION__,
- frameTimestamp);
- match = true;
- } else {
- int64_t delta = abs(bufferTimestamp - frameTimestamp);
- if ( delta < 1000000) {
- ALOGVV("%s: Found close match %" PRId64 " (delta %" PRId64 ")",
- __FUNCTION__, bufferTimestamp, delta);
- match = true;
- }
- }
- }
- if (match) {
- queueEntry.frame.acquire(frame);
- break;
- }
- }
- }
- }
+ // TODO: remove dependency on thread. For now, shut thread down right
+ // away.
+ return false;
}
void ZslProcessor::dumpZslQueue(int fd) const {
@@ -567,5 +502,174 @@
}
}
+bool ZslProcessor::isFixedFocusMode(uint8_t afMode) const {
+ switch (afMode) {
+ case ANDROID_CONTROL_AF_MODE_AUTO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
+ case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
+ case ANDROID_CONTROL_AF_MODE_MACRO:
+ return false;
+ break;
+ case ANDROID_CONTROL_AF_MODE_OFF:
+ case ANDROID_CONTROL_AF_MODE_EDOF:
+ return true;
+ default:
+ ALOGE("%s: unknown focus mode %d", __FUNCTION__, afMode);
+ return false;
+ }
+}
+
+nsecs_t ZslProcessor::getCandidateTimestampLocked(size_t* metadataIdx) const {
+ /**
+ * Find the smallest timestamp we know about so far
+ * - ensure that aeState is either converged or locked
+ */
+
+ size_t idx = 0;
+ nsecs_t minTimestamp = -1;
+
+ size_t emptyCount = mFrameList.size();
+
+ for (size_t j = 0; j < mFrameList.size(); j++) {
+ const CameraMetadata &frame = mFrameList[j];
+ if (!frame.isEmpty()) {
+
+ emptyCount--;
+
+ camera_metadata_ro_entry_t entry;
+ entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
+ if (entry.count == 0) {
+ ALOGE("%s: Can't find timestamp in frame!",
+ __FUNCTION__);
+ continue;
+ }
+ nsecs_t frameTimestamp = entry.data.i64[0];
+ if (minTimestamp > frameTimestamp || minTimestamp == -1) {
+
+ entry = frame.find(ANDROID_CONTROL_AE_STATE);
+
+ if (entry.count == 0) {
+ /**
+ * This is most likely a HAL bug. The aeState field is
+ * mandatory, so it should always be in a metadata packet.
+ */
+ ALOGW("%s: ZSL queue frame has no AE state field!",
+ __FUNCTION__);
+ continue;
+ }
+ if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
+ entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
+ ALOGVV("%s: ZSL queue frame AE state is %d, need "
+ "full capture", __FUNCTION__, entry.data.u8[0]);
+ continue;
+ }
+
+ entry = frame.find(ANDROID_CONTROL_AF_MODE);
+ if (entry.count == 0) {
+ ALOGW("%s: ZSL queue frame has no AF mode field!",
+ __FUNCTION__);
+ continue;
+ }
+ uint8_t afMode = entry.data.u8[0];
+ if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
+ // Skip all the ZSL buffer for manual AF mode, as we don't really
+ // know the af state.
+ continue;
+ }
+
+ // Check AF state if device has focuser and focus mode isn't fixed
+ if (mHasFocuser && !isFixedFocusMode(afMode)) {
+ // Make sure the candidate frame has good focus.
+ entry = frame.find(ANDROID_CONTROL_AF_STATE);
+ if (entry.count == 0) {
+ ALOGW("%s: ZSL queue frame has no AF state field!",
+ __FUNCTION__);
+ continue;
+ }
+ uint8_t afState = entry.data.u8[0];
+ if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
+ afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
+ afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+ ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
+ __FUNCTION__, afState);
+ continue;
+ }
+ }
+
+ minTimestamp = frameTimestamp;
+ idx = j;
+ }
+
+ ALOGVV("%s: Saw timestamp %" PRId64, __FUNCTION__, frameTimestamp);
+ }
+ }
+
+ if (emptyCount == mFrameList.size()) {
+ /**
+ * This could be mildly bad and means our ZSL was triggered before
+ * there were any frames yet received by the camera framework.
+ *
+ * This is a fairly corner case which can happen under:
+ * + a user presses the shutter button real fast when the camera starts
+ * (startPreview followed immediately by takePicture).
+ * + burst capture case (hitting shutter button as fast possible)
+ *
+ * If this happens in steady case (preview running for a while, call
+ * a single takePicture) then this might be a fwk bug.
+ */
+ ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
+ }
+
+ ALOGV("%s: Candidate timestamp %" PRId64 " (idx %zu), empty frames: %zu",
+ __FUNCTION__, minTimestamp, idx, emptyCount);
+
+ if (metadataIdx) {
+ *metadataIdx = idx;
+ }
+
+ return minTimestamp;
+}
+
+void ZslProcessor::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
+ // Intentionally left empty
+ // Although theoretically we could use this to get better dump info
+}
+
+void ZslProcessor::onBufferReleased(const BufferInfo& bufferInfo) {
+
+ // ignore output buffers
+ if (bufferInfo.mOutput) {
+ return;
+ }
+
+ // Lock mutex only once we know this is an input buffer returned to avoid
+ // potential deadlock
+ Mutex::Autolock l(mInputMutex);
+ // TODO: Verify that the buffer is in our queue by looking at timestamp
+ // theoretically unnecessary unless we change the following assumptions:
+ // -- only 1 buffer reprocessed at a time (which is the case now)
+
+ // Erase entire ZSL queue since we've now completed the capture and preview
+ // is stopped.
+ //
+ // We need to guarantee that if we do two back-to-back captures,
+ // the second won't use a buffer that's older/the same as the first, which
+ // is theoretically possible if we don't clear out the queue and the
+ // selection criteria is something like 'newest'. Clearing out the result
+ // metadata queue on a completed capture ensures we'll only use new timestamp.
+ // Calling clearZslQueueLocked is a guaranteed deadlock because this callback
+ // holds the Camera3Stream internal lock (mLock), and clearZslQueueLocked requires
+ // to hold the same lock.
+ // TODO: need figure out a way to clear the Zsl buffer queue properly. Right now
+ // it is safe not to do so, as back to back ZSL capture requires stop and start
+ // preview, which will flush ZSL queue automatically.
+ ALOGV("%s: Memory optimization, clearing ZSL queue",
+ __FUNCTION__);
+ clearZslResultQueueLocked();
+
+ // Required so we accept more ZSL requests
+ mState = RUNNING;
+}
+
}; // namespace camera2
}; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor.h b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
index 5870bd3..86c06c6 100644
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor.h
+++ b/services/camera/libcameraservice/api1/client2/ZslProcessor.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 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.
@@ -25,11 +25,9 @@
#include <gui/BufferItem.h>
#include <gui/BufferItemConsumer.h>
#include <camera/CameraMetadata.h>
-#include <camera/CaptureResult.h>
-#include "common/CameraDeviceBase.h"
-#include "api1/client2/ZslProcessorInterface.h"
#include "api1/client2/FrameProcessor.h"
+#include "device3/Camera3ZslStream.h"
namespace android {
@@ -38,45 +36,66 @@
namespace camera2 {
class CaptureSequencer;
-class Parameters;
+struct Parameters;
/***
- * ZSL queue processing
+ * ZSL queue processing for HALv3.0 or newer
*/
-class ZslProcessor:
+class ZslProcessor :
+ public camera3::Camera3StreamBufferListener,
virtual public Thread,
- virtual public BufferItemConsumer::FrameAvailableListener,
- virtual public FrameProcessor::FilteredListener,
- virtual public CameraDeviceBase::BufferReleasedListener,
- public ZslProcessorInterface {
+ virtual public FrameProcessor::FilteredListener {
public:
ZslProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
~ZslProcessor();
- // From mZslConsumer
- virtual void onFrameAvailable(const BufferItem& item);
- // From FrameProcessor
+ // From FrameProcessor::FilteredListener
virtual void onResultAvailable(const CaptureResult &result);
- virtual void onBufferReleased(buffer_handle_t *handle);
-
/**
****************************************
* ZslProcessorInterface implementation *
****************************************
*/
+ // Update the streams by recreating them if the size/format has changed
status_t updateStream(const Parameters ¶ms);
+
+ // Delete the underlying CameraDevice streams
status_t deleteStream();
- status_t disconnect();
+
+ // Get ID for use with android.request.outputStreams / inputStreams
int getStreamId() const;
+ /**
+ * Submits a ZSL capture request (id = requestId)
+ *
+ * An appropriate ZSL buffer is selected by the closest timestamp,
+ * then we push that buffer to be reprocessed by the HAL.
+ * A capture request is created and submitted on behalf of the client.
+ */
status_t pushToReprocess(int32_t requestId);
+
+ // Flush the ZSL buffer queue, freeing up all the buffers
status_t clearZslQueue();
void dump(int fd, const Vector<String16>& args) const;
+
+ protected:
+ /**
+ **********************************************
+ * Camera3StreamBufferListener implementation *
+ **********************************************
+ */
+ typedef camera3::Camera3StreamBufferListener::BufferInfo BufferInfo;
+ // Buffer was acquired by the HAL
+ virtual void onBufferAcquired(const BufferInfo& bufferInfo);
+ // Buffer was released by the HAL
+ virtual void onBufferReleased(const BufferInfo& bufferInfo);
+
private:
static const nsecs_t kWaitDuration = 10000000; // 10 ms
+ nsecs_t mLatestClearedBufferTimestamp;
enum {
RUNNING,
@@ -84,53 +103,52 @@
} mState;
wp<Camera2Client> mClient;
- wp<CameraDeviceBase> mDevice;
wp<CaptureSequencer> mSequencer;
- int mId;
- bool mDeleted;
+ const int mId;
mutable Mutex mInputMutex;
- bool mZslBufferAvailable;
- Condition mZslBufferAvailableSignal;
enum {
NO_STREAM = -1
};
int mZslStreamId;
- int mZslReprocessStreamId;
- sp<BufferItemConsumer> mZslConsumer;
- sp<Surface> mZslWindow;
+ sp<camera3::Camera3ZslStream> mZslStream;
struct ZslPair {
BufferItem buffer;
CameraMetadata frame;
};
- static const size_t kZslBufferDepth = 4;
- static const size_t kFrameListDepth = kZslBufferDepth * 2;
+ static const int32_t kDefaultMaxPipelineDepth = 4;
+ size_t mBufferQueueDepth;
+ size_t mFrameListDepth;
Vector<CameraMetadata> mFrameList;
size_t mFrameListHead;
ZslPair mNextPair;
Vector<ZslPair> mZslQueue;
- size_t mZslQueueHead;
- size_t mZslQueueTail;
CameraMetadata mLatestCapturedRequest;
+ bool mHasFocuser;
+
virtual bool threadLoop();
- status_t processNewZslBuffer();
-
- // Match up entries from frame list to buffers in ZSL queue
- void findMatchesLocked();
-
status_t clearZslQueueLocked();
+ void clearZslResultQueueLocked();
+
void dumpZslQueue(int id) const;
+
+ nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
+
+ bool isFixedFocusMode(uint8_t afMode) const;
+
+ // Update the post-processing metadata with the default still capture request template
+ status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
};
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
deleted file mode 100644
index 69620ac..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.cpp
+++ /dev/null
@@ -1,677 +0,0 @@
-/*
- * Copyright (C) 2013 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 "Camera2-ZslProcessor3"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0
-
-#ifdef LOG_NNDEBUG
-#define ALOGVV(...) ALOGV(__VA_ARGS__)
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-#include <inttypes.h>
-
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include <gui/Surface.h>
-
-#include "common/CameraDeviceBase.h"
-#include "api1/Camera2Client.h"
-#include "api1/client2/CaptureSequencer.h"
-#include "api1/client2/ZslProcessor3.h"
-#include "device3/Camera3Device.h"
-
-namespace android {
-namespace camera2 {
-
-ZslProcessor3::ZslProcessor3(
- sp<Camera2Client> client,
- wp<CaptureSequencer> sequencer):
- Thread(false),
- mLatestClearedBufferTimestamp(0),
- mState(RUNNING),
- mClient(client),
- mSequencer(sequencer),
- mId(client->getCameraId()),
- mZslStreamId(NO_STREAM),
- mFrameListHead(0),
- mZslQueueHead(0),
- mZslQueueTail(0),
- mHasFocuser(false) {
- // Initialize buffer queue and frame list based on pipeline max depth.
- size_t pipelineMaxDepth = kDefaultMaxPipelineDepth;
- if (client != 0) {
- sp<Camera3Device> device =
- static_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device != 0) {
- camera_metadata_ro_entry_t entry =
- device->info().find(ANDROID_REQUEST_PIPELINE_MAX_DEPTH);
- if (entry.count == 1) {
- pipelineMaxDepth = entry.data.u8[0];
- } else {
- ALOGW("%s: Unable to find the android.request.pipelineMaxDepth,"
- " use default pipeline max depth %zu", __FUNCTION__,
- kDefaultMaxPipelineDepth);
- }
-
- entry = device->info().find(ANDROID_LENS_INFO_MINIMUM_FOCUS_DISTANCE);
- if (entry.count > 0 && entry.data.f[0] != 0.) {
- mHasFocuser = true;
- }
- }
- }
-
- ALOGV("%s: Initialize buffer queue and frame list depth based on max pipeline depth (%d)",
- __FUNCTION__, pipelineMaxDepth);
- // Need to keep buffer queue longer than metadata queue because sometimes buffer arrives
- // earlier than metadata which causes the buffer corresponding to oldest metadata being
- // removed.
- mFrameListDepth = pipelineMaxDepth;
- mBufferQueueDepth = mFrameListDepth + 1;
-
-
- mZslQueue.insertAt(0, mBufferQueueDepth);
- mFrameList.insertAt(0, mFrameListDepth);
- sp<CaptureSequencer> captureSequencer = mSequencer.promote();
- if (captureSequencer != 0) captureSequencer->setZslProcessor(this);
-}
-
-ZslProcessor3::~ZslProcessor3() {
- ALOGV("%s: Exit", __FUNCTION__);
- deleteStream();
-}
-
-void ZslProcessor3::onResultAvailable(const CaptureResult &result) {
- ATRACE_CALL();
- ALOGV("%s:", __FUNCTION__);
- Mutex::Autolock l(mInputMutex);
- camera_metadata_ro_entry_t entry;
- entry = result.mMetadata.find(ANDROID_SENSOR_TIMESTAMP);
- nsecs_t timestamp = entry.data.i64[0];
- if (entry.count == 0) {
- ALOGE("%s: metadata doesn't have timestamp, skip this result", __FUNCTION__);
- return;
- }
-
- entry = result.mMetadata.find(ANDROID_REQUEST_FRAME_COUNT);
- if (entry.count == 0) {
- ALOGE("%s: metadata doesn't have frame number, skip this result", __FUNCTION__);
- return;
- }
- int32_t frameNumber = entry.data.i32[0];
-
- ALOGVV("Got preview metadata for frame %d with timestamp %" PRId64, frameNumber, timestamp);
-
- if (mState != RUNNING) return;
-
- // Corresponding buffer has been cleared. No need to push into mFrameList
- if (timestamp <= mLatestClearedBufferTimestamp) return;
-
- mFrameList.editItemAt(mFrameListHead) = result.mMetadata;
- mFrameListHead = (mFrameListHead + 1) % mFrameListDepth;
-}
-
-status_t ZslProcessor3::updateStream(const Parameters ¶ms) {
- ATRACE_CALL();
- ALOGV("%s: Configuring ZSL streams", __FUNCTION__);
- status_t res;
-
- Mutex::Autolock l(mInputMutex);
-
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
- sp<Camera3Device> device =
- static_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device == 0) {
- ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- if (mZslStreamId != NO_STREAM) {
- // Check if stream parameters have to change
- uint32_t currentWidth, currentHeight;
- res = device->getStreamInfo(mZslStreamId,
- ¤tWidth, ¤tHeight, 0, 0);
- if (res != OK) {
- ALOGE("%s: Camera %d: Error querying capture output stream info: "
- "%s (%d)", __FUNCTION__,
- client->getCameraId(), strerror(-res), res);
- return res;
- }
- if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
- currentHeight != (uint32_t)params.fastInfo.arrayHeight) {
- ALOGV("%s: Camera %d: Deleting stream %d since the buffer "
- "dimensions changed",
- __FUNCTION__, client->getCameraId(), mZslStreamId);
- res = device->deleteStream(mZslStreamId);
- if (res == -EBUSY) {
- ALOGV("%s: Camera %d: Device is busy, call updateStream again "
- " after it becomes idle", __FUNCTION__, mId);
- return res;
- } else if(res != OK) {
- ALOGE("%s: Camera %d: Unable to delete old output stream "
- "for ZSL: %s (%d)", __FUNCTION__,
- client->getCameraId(), strerror(-res), res);
- return res;
- }
- mZslStreamId = NO_STREAM;
- }
- }
-
- if (mZslStreamId == NO_STREAM) {
- // Create stream for HAL production
- // TODO: Sort out better way to select resolution for ZSL
-
- // Note that format specified internally in Camera3ZslStream
- res = device->createZslStream(
- params.fastInfo.arrayWidth, params.fastInfo.arrayHeight,
- mBufferQueueDepth,
- &mZslStreamId,
- &mZslStream);
- if (res != OK) {
- ALOGE("%s: Camera %d: Can't create ZSL stream: "
- "%s (%d)", __FUNCTION__, client->getCameraId(),
- strerror(-res), res);
- return res;
- }
-
- // Only add the camera3 buffer listener when the stream is created.
- mZslStream->addBufferListener(this);
- }
-
- client->registerFrameListener(Camera2Client::kPreviewRequestIdStart,
- Camera2Client::kPreviewRequestIdEnd,
- this,
- /*sendPartials*/false);
-
- return OK;
-}
-
-status_t ZslProcessor3::deleteStream() {
- ATRACE_CALL();
- status_t res;
-
- Mutex::Autolock l(mInputMutex);
-
- if (mZslStreamId != NO_STREAM) {
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- sp<Camera3Device> device =
- reinterpret_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device == 0) {
- ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- res = device->deleteStream(mZslStreamId);
- if (res != OK) {
- ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
- "%s (%d)", __FUNCTION__, client->getCameraId(),
- mZslStreamId, strerror(-res), res);
- return res;
- }
-
- mZslStreamId = NO_STREAM;
- }
- return OK;
-}
-
-int ZslProcessor3::getStreamId() const {
- Mutex::Autolock l(mInputMutex);
- return mZslStreamId;
-}
-
-status_t ZslProcessor3::updateRequestWithDefaultStillRequest(CameraMetadata &request) const {
- sp<Camera2Client> client = mClient.promote();
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
- sp<Camera3Device> device =
- static_cast<Camera3Device*>(client->getCameraDevice().get());
- if (device == 0) {
- ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- CameraMetadata stillTemplate;
- device->createDefaultRequest(CAMERA3_TEMPLATE_STILL_CAPTURE, &stillTemplate);
-
- // Find some of the post-processing tags, and assign the value from template to the request.
- // Only check the aberration mode and noise reduction mode for now, as they are very important
- // for image quality.
- uint32_t postProcessingTags[] = {
- ANDROID_NOISE_REDUCTION_MODE,
- ANDROID_COLOR_CORRECTION_ABERRATION_MODE,
- ANDROID_COLOR_CORRECTION_MODE,
- ANDROID_TONEMAP_MODE,
- ANDROID_SHADING_MODE,
- ANDROID_HOT_PIXEL_MODE,
- ANDROID_EDGE_MODE
- };
-
- camera_metadata_entry_t entry;
- for (size_t i = 0; i < sizeof(postProcessingTags) / sizeof(uint32_t); i++) {
- entry = stillTemplate.find(postProcessingTags[i]);
- if (entry.count > 0) {
- request.update(postProcessingTags[i], entry.data.u8, 1);
- }
- }
-
- return OK;
-}
-
-status_t ZslProcessor3::pushToReprocess(int32_t requestId) {
- ALOGV("%s: Send in reprocess request with id %d",
- __FUNCTION__, requestId);
- Mutex::Autolock l(mInputMutex);
- status_t res;
- sp<Camera2Client> client = mClient.promote();
-
- if (client == 0) {
- ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
- return INVALID_OPERATION;
- }
-
- IF_ALOGV() {
- dumpZslQueue(-1);
- }
-
- size_t metadataIdx;
- nsecs_t candidateTimestamp = getCandidateTimestampLocked(&metadataIdx);
-
- if (candidateTimestamp == -1) {
- ALOGE("%s: Could not find good candidate for ZSL reprocessing",
- __FUNCTION__);
- return NOT_ENOUGH_DATA;
- }
-
- res = mZslStream->enqueueInputBufferByTimestamp(candidateTimestamp,
- /*actualTimestamp*/NULL);
-
- if (res == mZslStream->NO_BUFFER_AVAILABLE) {
- ALOGV("%s: No ZSL buffers yet", __FUNCTION__);
- return NOT_ENOUGH_DATA;
- } else if (res != OK) {
- ALOGE("%s: Unable to push buffer for reprocessing: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- {
- CameraMetadata request = mFrameList[metadataIdx];
-
- // Verify that the frame is reasonable for reprocessing
-
- camera_metadata_entry_t entry;
- entry = request.find(ANDROID_CONTROL_AE_STATE);
- if (entry.count == 0) {
- ALOGE("%s: ZSL queue frame has no AE state field!",
- __FUNCTION__);
- return BAD_VALUE;
- }
- if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
- entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
- ALOGV("%s: ZSL queue frame AE state is %d, need full capture",
- __FUNCTION__, entry.data.u8[0]);
- return NOT_ENOUGH_DATA;
- }
-
- uint8_t requestType = ANDROID_REQUEST_TYPE_REPROCESS;
- res = request.update(ANDROID_REQUEST_TYPE,
- &requestType, 1);
- if (res != OK) {
- ALOGE("%s: Unable to update request type",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- int32_t inputStreams[1] =
- { mZslStreamId };
- res = request.update(ANDROID_REQUEST_INPUT_STREAMS,
- inputStreams, 1);
- if (res != OK) {
- ALOGE("%s: Unable to update request input streams",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- uint8_t captureIntent =
- static_cast<uint8_t>(ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE);
- res = request.update(ANDROID_CONTROL_CAPTURE_INTENT,
- &captureIntent, 1);
- if (res != OK ) {
- ALOGE("%s: Unable to update request capture intent",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- // TODO: Shouldn't we also update the latest preview frame?
- int32_t outputStreams[1] =
- { client->getCaptureStreamId() };
- res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,
- outputStreams, 1);
- if (res != OK) {
- ALOGE("%s: Unable to update request output streams",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- res = request.update(ANDROID_REQUEST_ID,
- &requestId, 1);
- if (res != OK ) {
- ALOGE("%s: Unable to update frame to a reprocess request",
- __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- res = client->stopStream();
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
- "%s (%d)",
- __FUNCTION__, client->getCameraId(), strerror(-res), res);
- return INVALID_OPERATION;
- }
-
- // Update JPEG settings
- {
- SharedParameters::Lock l(client->getParameters());
- res = l.mParameters.updateRequestJpeg(&request);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL "
- "capture request: %s (%d)", __FUNCTION__,
- client->getCameraId(),
- strerror(-res), res);
- return res;
- }
- }
-
- // Update post-processing settings
- res = updateRequestWithDefaultStillRequest(request);
- if (res != OK) {
- ALOGW("%s: Unable to update post-processing tags, the reprocessed image quality "
- "may be compromised", __FUNCTION__);
- }
-
- mLatestCapturedRequest = request;
- res = client->getCameraDevice()->capture(request);
- if (res != OK ) {
- ALOGE("%s: Unable to send ZSL reprocess request to capture: %s"
- " (%d)", __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- mState = LOCKED;
- }
-
- return OK;
-}
-
-status_t ZslProcessor3::clearZslQueue() {
- Mutex::Autolock l(mInputMutex);
- // If in middle of capture, can't clear out queue
- if (mState == LOCKED) return OK;
-
- return clearZslQueueLocked();
-}
-
-status_t ZslProcessor3::clearZslQueueLocked() {
- if (mZslStream != 0) {
- // clear result metadata list first.
- clearZslResultQueueLocked();
- return mZslStream->clearInputRingBuffer(&mLatestClearedBufferTimestamp);
- }
- return OK;
-}
-
-void ZslProcessor3::clearZslResultQueueLocked() {
- mFrameList.clear();
- mFrameListHead = 0;
- mFrameList.insertAt(0, mFrameListDepth);
-}
-
-void ZslProcessor3::dump(int fd, const Vector<String16>& /*args*/) const {
- Mutex::Autolock l(mInputMutex);
- if (!mLatestCapturedRequest.isEmpty()) {
- String8 result(" Latest ZSL capture request:\n");
- write(fd, result.string(), result.size());
- mLatestCapturedRequest.dump(fd, 2, 6);
- } else {
- String8 result(" Latest ZSL capture request: none yet\n");
- write(fd, result.string(), result.size());
- }
- dumpZslQueue(fd);
-}
-
-bool ZslProcessor3::threadLoop() {
- // TODO: remove dependency on thread. For now, shut thread down right
- // away.
- return false;
-}
-
-void ZslProcessor3::dumpZslQueue(int fd) const {
- String8 header("ZSL queue contents:");
- String8 indent(" ");
- ALOGV("%s", header.string());
- if (fd != -1) {
- header = indent + header + "\n";
- write(fd, header.string(), header.size());
- }
- for (size_t i = 0; i < mZslQueue.size(); i++) {
- const ZslPair &queueEntry = mZslQueue[i];
- nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp;
- camera_metadata_ro_entry_t entry;
- nsecs_t frameTimestamp = 0;
- int frameAeState = -1;
- if (!queueEntry.frame.isEmpty()) {
- entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP);
- if (entry.count > 0) frameTimestamp = entry.data.i64[0];
- entry = queueEntry.frame.find(ANDROID_CONTROL_AE_STATE);
- if (entry.count > 0) frameAeState = entry.data.u8[0];
- }
- String8 result =
- String8::format(" %zu: b: %" PRId64 "\tf: %" PRId64 ", AE state: %d", i,
- bufferTimestamp, frameTimestamp, frameAeState);
- ALOGV("%s", result.string());
- if (fd != -1) {
- result = indent + result + "\n";
- write(fd, result.string(), result.size());
- }
-
- }
-}
-
-bool ZslProcessor3::isFixedFocusMode(uint8_t afMode) const {
- switch (afMode) {
- case ANDROID_CONTROL_AF_MODE_AUTO:
- case ANDROID_CONTROL_AF_MODE_CONTINUOUS_VIDEO:
- case ANDROID_CONTROL_AF_MODE_CONTINUOUS_PICTURE:
- case ANDROID_CONTROL_AF_MODE_MACRO:
- return false;
- break;
- case ANDROID_CONTROL_AF_MODE_OFF:
- case ANDROID_CONTROL_AF_MODE_EDOF:
- return true;
- default:
- ALOGE("%s: unknown focus mode %d", __FUNCTION__, afMode);
- return false;
- }
-}
-
-nsecs_t ZslProcessor3::getCandidateTimestampLocked(size_t* metadataIdx) const {
- /**
- * Find the smallest timestamp we know about so far
- * - ensure that aeState is either converged or locked
- */
-
- size_t idx = 0;
- nsecs_t minTimestamp = -1;
-
- size_t emptyCount = mFrameList.size();
-
- for (size_t j = 0; j < mFrameList.size(); j++) {
- const CameraMetadata &frame = mFrameList[j];
- if (!frame.isEmpty()) {
-
- emptyCount--;
-
- camera_metadata_ro_entry_t entry;
- entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
- if (entry.count == 0) {
- ALOGE("%s: Can't find timestamp in frame!",
- __FUNCTION__);
- continue;
- }
- nsecs_t frameTimestamp = entry.data.i64[0];
- if (minTimestamp > frameTimestamp || minTimestamp == -1) {
-
- entry = frame.find(ANDROID_CONTROL_AE_STATE);
-
- if (entry.count == 0) {
- /**
- * This is most likely a HAL bug. The aeState field is
- * mandatory, so it should always be in a metadata packet.
- */
- ALOGW("%s: ZSL queue frame has no AE state field!",
- __FUNCTION__);
- continue;
- }
- if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED &&
- entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) {
- ALOGVV("%s: ZSL queue frame AE state is %d, need "
- "full capture", __FUNCTION__, entry.data.u8[0]);
- continue;
- }
-
- entry = frame.find(ANDROID_CONTROL_AF_MODE);
- if (entry.count == 0) {
- ALOGW("%s: ZSL queue frame has no AF mode field!",
- __FUNCTION__);
- continue;
- }
- uint8_t afMode = entry.data.u8[0];
- if (afMode == ANDROID_CONTROL_AF_MODE_OFF) {
- // Skip all the ZSL buffer for manual AF mode, as we don't really
- // know the af state.
- continue;
- }
-
- // Check AF state if device has focuser and focus mode isn't fixed
- if (mHasFocuser && !isFixedFocusMode(afMode)) {
- // Make sure the candidate frame has good focus.
- entry = frame.find(ANDROID_CONTROL_AF_STATE);
- if (entry.count == 0) {
- ALOGW("%s: ZSL queue frame has no AF state field!",
- __FUNCTION__);
- continue;
- }
- uint8_t afState = entry.data.u8[0];
- if (afState != ANDROID_CONTROL_AF_STATE_PASSIVE_FOCUSED &&
- afState != ANDROID_CONTROL_AF_STATE_FOCUSED_LOCKED &&
- afState != ANDROID_CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
- ALOGVV("%s: ZSL queue frame AF state is %d is not good for capture, skip it",
- __FUNCTION__, afState);
- continue;
- }
- }
-
- minTimestamp = frameTimestamp;
- idx = j;
- }
-
- ALOGVV("%s: Saw timestamp %" PRId64, __FUNCTION__, frameTimestamp);
- }
- }
-
- if (emptyCount == mFrameList.size()) {
- /**
- * This could be mildly bad and means our ZSL was triggered before
- * there were any frames yet received by the camera framework.
- *
- * This is a fairly corner case which can happen under:
- * + a user presses the shutter button real fast when the camera starts
- * (startPreview followed immediately by takePicture).
- * + burst capture case (hitting shutter button as fast possible)
- *
- * If this happens in steady case (preview running for a while, call
- * a single takePicture) then this might be a fwk bug.
- */
- ALOGW("%s: ZSL queue has no metadata frames", __FUNCTION__);
- }
-
- ALOGV("%s: Candidate timestamp %" PRId64 " (idx %zu), empty frames: %zu",
- __FUNCTION__, minTimestamp, idx, emptyCount);
-
- if (metadataIdx) {
- *metadataIdx = idx;
- }
-
- return minTimestamp;
-}
-
-void ZslProcessor3::onBufferAcquired(const BufferInfo& /*bufferInfo*/) {
- // Intentionally left empty
- // Although theoretically we could use this to get better dump info
-}
-
-void ZslProcessor3::onBufferReleased(const BufferInfo& bufferInfo) {
-
- // ignore output buffers
- if (bufferInfo.mOutput) {
- return;
- }
-
- // Lock mutex only once we know this is an input buffer returned to avoid
- // potential deadlock
- Mutex::Autolock l(mInputMutex);
- // TODO: Verify that the buffer is in our queue by looking at timestamp
- // theoretically unnecessary unless we change the following assumptions:
- // -- only 1 buffer reprocessed at a time (which is the case now)
-
- // Erase entire ZSL queue since we've now completed the capture and preview
- // is stopped.
- //
- // We need to guarantee that if we do two back-to-back captures,
- // the second won't use a buffer that's older/the same as the first, which
- // is theoretically possible if we don't clear out the queue and the
- // selection criteria is something like 'newest'. Clearing out the result
- // metadata queue on a completed capture ensures we'll only use new timestamp.
- // Calling clearZslQueueLocked is a guaranteed deadlock because this callback
- // holds the Camera3Stream internal lock (mLock), and clearZslQueueLocked requires
- // to hold the same lock.
- // TODO: need figure out a way to clear the Zsl buffer queue properly. Right now
- // it is safe not to do so, as back to back ZSL capture requires stop and start
- // preview, which will flush ZSL queue automatically.
- ALOGV("%s: Memory optimization, clearing ZSL queue",
- __FUNCTION__);
- clearZslResultQueueLocked();
-
- // Required so we accept more ZSL requests
- mState = RUNNING;
-}
-
-}; // namespace camera2
-}; // namespace android
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h b/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
deleted file mode 100644
index 2960478..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessor3.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSOR3_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSOR3_H
-
-#include <utils/Thread.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-#include <utils/Mutex.h>
-#include <utils/Condition.h>
-#include <gui/BufferItem.h>
-#include <gui/BufferItemConsumer.h>
-#include <camera/CameraMetadata.h>
-
-#include "api1/client2/FrameProcessor.h"
-#include "api1/client2/ZslProcessorInterface.h"
-#include "device3/Camera3ZslStream.h"
-
-namespace android {
-
-class Camera2Client;
-
-namespace camera2 {
-
-class CaptureSequencer;
-class Parameters;
-
-/***
- * ZSL queue processing
- */
-class ZslProcessor3 :
- public ZslProcessorInterface,
- public camera3::Camera3StreamBufferListener,
- virtual public Thread,
- virtual public FrameProcessor::FilteredListener {
- public:
- ZslProcessor3(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
- ~ZslProcessor3();
-
- // From FrameProcessor::FilteredListener
- virtual void onResultAvailable(const CaptureResult &result);
-
- /**
- ****************************************
- * ZslProcessorInterface implementation *
- ****************************************
- */
-
- virtual status_t updateStream(const Parameters ¶ms);
- virtual status_t deleteStream();
- virtual int getStreamId() const;
-
- virtual status_t pushToReprocess(int32_t requestId);
- virtual status_t clearZslQueue();
-
- void dump(int fd, const Vector<String16>& args) const;
-
- protected:
- /**
- **********************************************
- * Camera3StreamBufferListener implementation *
- **********************************************
- */
- typedef camera3::Camera3StreamBufferListener::BufferInfo BufferInfo;
- // Buffer was acquired by the HAL
- virtual void onBufferAcquired(const BufferInfo& bufferInfo);
- // Buffer was released by the HAL
- virtual void onBufferReleased(const BufferInfo& bufferInfo);
-
- private:
- static const nsecs_t kWaitDuration = 10000000; // 10 ms
- nsecs_t mLatestClearedBufferTimestamp;
-
- enum {
- RUNNING,
- LOCKED
- } mState;
-
- wp<Camera2Client> mClient;
- wp<CaptureSequencer> mSequencer;
-
- const int mId;
-
- mutable Mutex mInputMutex;
-
- enum {
- NO_STREAM = -1
- };
-
- int mZslStreamId;
- sp<camera3::Camera3ZslStream> mZslStream;
-
- struct ZslPair {
- BufferItem buffer;
- CameraMetadata frame;
- };
-
- static const int32_t kDefaultMaxPipelineDepth = 4;
- size_t mBufferQueueDepth;
- size_t mFrameListDepth;
- Vector<CameraMetadata> mFrameList;
- size_t mFrameListHead;
-
- ZslPair mNextPair;
-
- Vector<ZslPair> mZslQueue;
- size_t mZslQueueHead;
- size_t mZslQueueTail;
-
- CameraMetadata mLatestCapturedRequest;
-
- bool mHasFocuser;
-
- virtual bool threadLoop();
-
- status_t clearZslQueueLocked();
-
- void clearZslResultQueueLocked();
-
- void dumpZslQueue(int id) const;
-
- nsecs_t getCandidateTimestampLocked(size_t* metadataIdx) const;
-
- bool isFixedFocusMode(uint8_t afMode) const;
-
- // Update the post-processing metadata with the default still capture request template
- status_t updateRequestWithDefaultStillRequest(CameraMetadata &request) const;
-};
-
-
-}; //namespace camera2
-}; //namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
deleted file mode 100644
index 9efeaba..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "ZslProcessorInterface.h"
-
-namespace android {
-namespace camera2 {
-
-status_t ZslProcessorInterface::disconnect() {
- return OK;
-}
-
-}; //namespace camera2
-}; //namespace android
-
diff --git a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h b/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
deleted file mode 100644
index 9e266e7..0000000
--- a/services/camera/libcameraservice/api1/client2/ZslProcessorInterface.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2_ZSLPROCESSORINTERFACE_H
-
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <utils/String16.h>
-#include <utils/Vector.h>
-
-namespace android {
-namespace camera2 {
-
-class Parameters;
-
-class ZslProcessorInterface : virtual public RefBase {
-public:
-
- // Get ID for use with android.request.outputStreams / inputStreams
- virtual int getStreamId() const = 0;
-
- // Update the streams by recreating them if the size/format has changed
- virtual status_t updateStream(const Parameters& params) = 0;
-
- // Delete the underlying CameraDevice streams
- virtual status_t deleteStream() = 0;
-
- // Clear any additional state necessary before the CameraDevice is disconnected
- virtual status_t disconnect();
-
- /**
- * Submits a ZSL capture request (id = requestId)
- *
- * An appropriate ZSL buffer is selected by the closest timestamp,
- * then we push that buffer to be reprocessed by the HAL.
- * A capture request is created and submitted on behalf of the client.
- */
- virtual status_t pushToReprocess(int32_t requestId) = 0;
-
- // Flush the ZSL buffer queue, freeing up all the buffers
- virtual status_t clearZslQueue() = 0;
-
- // (Debugging only) Dump the current state to the specified file descriptor
- virtual void dump(int fd, const Vector<String16>& args) const = 0;
-};
-
-}; //namespace camera2
-}; //namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index 5732f80..82c8fe9 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -31,7 +31,7 @@
#include "api2/CameraDeviceClient.h"
-#include "CameraDeviceFactory.h"
+#include "device3/Camera3Device.h"
namespace android {
using namespace camera2;
@@ -62,7 +62,7 @@
String8(clientPackageName).string(), clientPid, clientUid);
mInitialClientPid = clientPid;
- mDevice = CameraDeviceFactory::createDevice(cameraId);
+ mDevice = new Camera3Device(cameraId);
LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.h b/services/camera/libcameraservice/common/Camera2ClientBase.h
index 220c5ad..53122dc 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.h
@@ -125,7 +125,7 @@
// that mBinderSerializationLock is locked when they're called
mutable Mutex mBinderSerializationLock;
- /** CameraDeviceBase instance wrapping HAL2+ entry */
+ /** CameraDeviceBase instance wrapping HAL3+ entry */
const int mDeviceVersion;
sp<CameraDeviceBase> mDevice;
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index 16b8aba..d1c79d0 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -27,15 +27,10 @@
void CameraModule::deriveCameraCharacteristicsKeys(
uint32_t deviceVersion, CameraMetadata &chars) {
ATRACE_CALL();
- // HAL1 devices should not reach here
- if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
- ALOGV("%s: Cannot derive keys for HAL version < 2.0");
- return;
- }
+ Vector<int32_t> derivedCharKeys;
// Keys added in HAL3.3
if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_3) {
- const size_t NUM_DERIVED_KEYS_HAL3_3 = 5;
Vector<uint8_t> controlModes;
uint8_t data = ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE;
chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
@@ -107,18 +102,11 @@
chars.update(ANDROID_SHADING_AVAILABLE_MODES, lscModes);
chars.update(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES, lscMapModes);
- entry = chars.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
- Vector<int32_t> availableCharsKeys;
- availableCharsKeys.setCapacity(entry.count + NUM_DERIVED_KEYS_HAL3_3);
- for (size_t i = 0; i < entry.count; i++) {
- availableCharsKeys.push(entry.data.i32[i]);
- }
- availableCharsKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
- availableCharsKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
- availableCharsKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
- availableCharsKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
- availableCharsKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
- chars.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharsKeys);
+ derivedCharKeys.push(ANDROID_CONTROL_AE_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AWB_LOCK_AVAILABLE);
+ derivedCharKeys.push(ANDROID_CONTROL_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_SHADING_AVAILABLE_MODES);
+ derivedCharKeys.push(ANDROID_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES);
// Need update android.control.availableHighSpeedVideoConfigurations since HAL3.3
// adds batch size to this array.
@@ -137,6 +125,44 @@
}
}
+ // Keys added in HAL3.4
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_4) {
+ // Check if HAL supports RAW_OPAQUE output
+ camera_metadata_entry entry = chars.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);
+ bool supportRawOpaque = false;
+ const int STREAM_CONFIGURATION_SIZE = 4;
+ const int STREAM_FORMAT_OFFSET = 0;
+ const int STREAM_WIDTH_OFFSET = 1;
+ const int STREAM_HEIGHT_OFFSET = 2;
+ const int STREAM_IS_INPUT_OFFSET = 3;
+ Vector<int32_t> rawOpaqueSizes;
+
+ for (size_t i=0; i < entry.count; i += STREAM_CONFIGURATION_SIZE) {
+ int32_t format = entry.data.i32[i + STREAM_FORMAT_OFFSET];
+ int32_t width = entry.data.i32[i + STREAM_WIDTH_OFFSET];
+ int32_t height = entry.data.i32[i + STREAM_HEIGHT_OFFSET];
+ int32_t isInput = entry.data.i32[i + STREAM_IS_INPUT_OFFSET];
+ if (isInput == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
+ format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ supportRawOpaque = true;
+ rawOpaqueSizes.push(width);
+ rawOpaqueSizes.push(height);
+ // 2 bytes per pixel. This rough estimation is only used when
+ // HAL does not fill in the opaque raw size
+ rawOpaqueSizes.push(width * height *2);
+ }
+ }
+
+ if (supportRawOpaque) {
+ entry = chars.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ if (entry.count == 0) {
+ // Fill in estimated value if HAL does not list it
+ chars.update(ANDROID_SENSOR_OPAQUE_RAW_SIZE, rawOpaqueSizes);
+ derivedCharKeys.push(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ }
+ }
+ }
+
// Always add a default for the pre-correction active array if the vendor chooses to omit this
camera_metadata_entry entry = chars.find(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
if (entry.count == 0) {
@@ -144,8 +170,21 @@
entry = chars.find(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE);
preCorrectionArray.appendArray(entry.data.i32, entry.count);
chars.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE, preCorrectionArray);
+ derivedCharKeys.push(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
}
+ // Add those newly added keys to AVAILABLE_CHARACTERISTICS_KEYS
+ // This has to be done at this end of this function.
+ entry = chars.find(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS);
+ Vector<int32_t> availableCharsKeys;
+ availableCharsKeys.setCapacity(entry.count + derivedCharKeys.size());
+ for (size_t i = 0; i < entry.count; i++) {
+ availableCharsKeys.push(entry.data.i32[i]);
+ }
+ for (size_t i = 0; i < derivedCharKeys.size(); i++) {
+ availableCharsKeys.push(derivedCharKeys[i]);
+ }
+ chars.update(ANDROID_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS, availableCharsKeys);
return;
}
@@ -196,6 +235,9 @@
int ret;
ATRACE_BEGIN("camera_module->get_camera_info");
ret = mModule->get_camera_info(cameraId, info);
+ // Fill in this so CameraService won't be confused by
+ // possibly 0 device_version
+ info->device_version = CAMERA_DEVICE_API_VERSION_1_0;
ATRACE_END();
return ret;
}
@@ -211,7 +253,7 @@
return ret;
}
int deviceVersion = rawInfo.device_version;
- if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
+ if (deviceVersion < CAMERA_DEVICE_API_VERSION_3_0) {
// static_camera_characteristics is invalid
*info = rawInfo;
return ret;
diff --git a/services/camera/libcameraservice/device2/Camera2Device.cpp b/services/camera/libcameraservice/device2/Camera2Device.cpp
deleted file mode 100644
index d74f976..0000000
--- a/services/camera/libcameraservice/device2/Camera2Device.cpp
+++ /dev/null
@@ -1,1618 +0,0 @@
-/*
- * Copyright (C) 2012 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 "Camera2-Device"
-#define ATRACE_TAG ATRACE_TAG_CAMERA
-//#define LOG_NDEBUG 0
-//#define LOG_NNDEBUG 0 // Per-frame verbose logging
-
-#ifdef LOG_NNDEBUG
-#define ALOGVV(...) ALOGV(__VA_ARGS__)
-#else
-#define ALOGVV(...) ((void)0)
-#endif
-
-#include <inttypes.h>
-#include <utils/Log.h>
-#include <utils/Trace.h>
-#include <utils/Timers.h>
-#include "Camera2Device.h"
-#include "CameraService.h"
-
-namespace android {
-
-Camera2Device::Camera2Device(int id):
- mId(id),
- mHal2Device(NULL)
-{
- ATRACE_CALL();
- ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
-}
-
-Camera2Device::~Camera2Device()
-{
- ATRACE_CALL();
- ALOGV("%s: Tearing down for camera id %d", __FUNCTION__, mId);
- disconnect();
-}
-
-int Camera2Device::getId() const {
- return mId;
-}
-
-status_t Camera2Device::initialize(CameraModule *module)
-{
- ATRACE_CALL();
- ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);
- if (mHal2Device != NULL) {
- ALOGE("%s: Already initialized!", __FUNCTION__);
- return INVALID_OPERATION;
- }
-
- status_t res;
- char name[10];
- snprintf(name, sizeof(name), "%d", mId);
-
- camera2_device_t *device;
-
- res = module->open(name, reinterpret_cast<hw_device_t**>(&device));
-
- if (res != OK) {
- ALOGE("%s: Could not open camera %d: %s (%d)", __FUNCTION__,
- mId, strerror(-res), res);
- return res;
- }
-
- if (device->common.version != CAMERA_DEVICE_API_VERSION_2_0) {
- ALOGE("%s: Could not open camera %d: "
- "Camera device is not version %x, reports %x instead",
- __FUNCTION__, mId, CAMERA_DEVICE_API_VERSION_2_0,
- device->common.version);
- device->common.close(&device->common);
- return BAD_VALUE;
- }
-
- camera_info info;
- res = module->getCameraInfo(mId, &info);
- if (res != OK ) return res;
-
- if (info.device_version != device->common.version) {
- ALOGE("%s: HAL reporting mismatched camera_info version (%x)"
- " and device version (%x).", __FUNCTION__,
- device->common.version, info.device_version);
- device->common.close(&device->common);
- return BAD_VALUE;
- }
-
- res = mRequestQueue.setConsumerDevice(device);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to connect request queue to device: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- device->common.close(&device->common);
- return res;
- }
- res = mFrameQueue.setProducerDevice(device);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to connect frame queue to device: %s (%d)",
- __FUNCTION__, mId, strerror(-res), res);
- device->common.close(&device->common);
- return res;
- }
-
- res = device->ops->set_notify_callback(device, notificationCallback,
- NULL);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to initialize notification callback!",
- __FUNCTION__, mId);
- device->common.close(&device->common);
- return res;
- }
-
- mDeviceInfo = info.static_camera_characteristics;
- mHal2Device = device;
- mDeviceVersion = device->common.version;
-
- return OK;
-}
-
-status_t Camera2Device::disconnect() {
- ATRACE_CALL();
- status_t res = OK;
- if (mHal2Device) {
- ALOGV("%s: Closing device for camera %d", __FUNCTION__, mId);
-
- int inProgressCount = mHal2Device->ops->get_in_progress_count(mHal2Device);
- if (inProgressCount > 0) {
- ALOGW("%s: Closing camera device %d with %d requests in flight!",
- __FUNCTION__, mId, inProgressCount);
- }
- mReprocessStreams.clear();
- mStreams.clear();
- res = mHal2Device->common.close(&mHal2Device->common);
- if (res != OK) {
- ALOGE("%s: Could not close camera %d: %s (%d)",
- __FUNCTION__,
- mId, strerror(-res), res);
- }
- mHal2Device = NULL;
- ALOGV("%s: Shutdown complete", __FUNCTION__);
- }
- return res;
-}
-
-status_t Camera2Device::dump(int fd, const Vector<String16>& args) {
- ATRACE_CALL();
- String8 result;
- int detailLevel = 0;
- int n = args.size();
- String16 detailOption("-d");
- for (int i = 0; i + 1 < n; i++) {
- if (args[i] == detailOption) {
- String8 levelStr(args[i+1]);
- detailLevel = atoi(levelStr.string());
- }
- }
-
- result.appendFormat(" Camera2Device[%d] dump (detail level %d):\n",
- mId, detailLevel);
-
- if (detailLevel > 0) {
- result = " Request queue contents:\n";
- write(fd, result.string(), result.size());
- mRequestQueue.dump(fd, args);
-
- result = " Frame queue contents:\n";
- write(fd, result.string(), result.size());
- mFrameQueue.dump(fd, args);
- }
-
- result = " Active streams:\n";
- write(fd, result.string(), result.size());
- for (StreamList::iterator s = mStreams.begin(); s != mStreams.end(); s++) {
- (*s)->dump(fd, args);
- }
-
- result = " HAL device dump:\n";
- write(fd, result.string(), result.size());
-
- status_t res;
- res = mHal2Device->ops->dump(mHal2Device, fd);
-
- return res;
-}
-
-const CameraMetadata& Camera2Device::info() const {
- ALOGVV("%s: E", __FUNCTION__);
-
- return mDeviceInfo;
-}
-
-status_t Camera2Device::capture(CameraMetadata &request, int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
-
- mRequestQueue.enqueue(request.release());
- return OK;
-}
-
-status_t Camera2Device::captureList(const List<const CameraMetadata> &requests,
- int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGE("%s: Camera2Device burst capture not implemented", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-status_t Camera2Device::setStreamingRequest(const CameraMetadata &request,
- int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- CameraMetadata streamRequest(request);
- return mRequestQueue.setStreamSlot(streamRequest.release());
-}
-
-status_t Camera2Device::setStreamingRequestList(const List<const CameraMetadata> &requests,
- int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- ALOGE("%s, Camera2Device streaming burst not implemented", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-status_t Camera2Device::clearStreamingRequest(int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
- return mRequestQueue.setStreamSlot(NULL);
-}
-
-status_t Camera2Device::waitUntilRequestReceived(int32_t requestId, nsecs_t timeout) {
- ATRACE_CALL();
- return mRequestQueue.waitForDequeue(requestId, timeout);
-}
-
-status_t Camera2Device::createStream(sp<Surface> consumer,
- uint32_t width, uint32_t height, int format,
- android_dataspace /*dataSpace*/, camera3_stream_rotation_t rotation, int *id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- sp<StreamAdapter> stream = new StreamAdapter(mHal2Device);
- size_t size = 0;
- if (format == HAL_PIXEL_FORMAT_BLOB) {
- size = getJpegBufferSize(width, height);
- }
- res = stream->connectToDevice(consumer, width, height, format, size);
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create stream (%d x %d, format %x):"
- "%s (%d)",
- __FUNCTION__, mId, width, height, format, strerror(-res), res);
- return res;
- }
-
- *id = stream->getId();
-
- mStreams.push_back(stream);
- return OK;
-}
-
-ssize_t Camera2Device::getJpegBufferSize(uint32_t width, uint32_t height) const {
- // Always give the max jpeg buffer size regardless of the actual jpeg resolution.
- camera_metadata_ro_entry jpegBufMaxSize = mDeviceInfo.find(ANDROID_JPEG_MAX_SIZE);
- if (jpegBufMaxSize.count == 0) {
- ALOGE("%s: Camera %d: Can't find maximum JPEG size in static metadata!", __FUNCTION__, mId);
- return BAD_VALUE;
- }
-
- return jpegBufMaxSize.data.i32[0];
-}
-
-status_t Camera2Device::createReprocessStreamFromStream(int outputId, int *id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- bool found = false;
- StreamList::iterator streamI;
- for (streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == outputId) {
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Output stream %d doesn't exist; can't create "
- "reprocess stream from it!", __FUNCTION__, mId, outputId);
- return BAD_VALUE;
- }
-
- sp<ReprocessStreamAdapter> stream = new ReprocessStreamAdapter(mHal2Device);
-
- res = stream->connectToDevice((*streamI));
- if (res != OK) {
- ALOGE("%s: Camera %d: Unable to create reprocessing stream from "\
- "stream %d: %s (%d)", __FUNCTION__, mId, outputId,
- strerror(-res), res);
- return res;
- }
-
- *id = stream->getId();
-
- mReprocessStreams.push_back(stream);
- return OK;
-}
-
-
-status_t Camera2Device::getStreamInfo(int id,
- uint32_t *width, uint32_t *height,
- uint32_t *format, android_dataspace *dataSpace) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- StreamList::iterator streamI;
- for (streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Stream %d does not exist",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
-
- if (width) *width = (*streamI)->getWidth();
- if (height) *height = (*streamI)->getHeight();
- if (format) *format = (*streamI)->getFormat();
- if (dataSpace) *dataSpace = HAL_DATASPACE_UNKNOWN;
-
- return OK;
-}
-
-status_t Camera2Device::setStreamTransform(int id,
- int transform) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- StreamList::iterator streamI;
- for (streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Stream %d does not exist",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
-
- return (*streamI)->setTransform(transform);
-}
-
-status_t Camera2Device::deleteStream(int id) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- for (StreamList::iterator streamI = mStreams.begin();
- streamI != mStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- status_t res = (*streamI)->release();
- if (res != OK) {
- ALOGE("%s: Unable to release stream %d from HAL device: "
- "%s (%d)", __FUNCTION__, id, strerror(-res), res);
- return res;
- }
- mStreams.erase(streamI);
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Unable to find stream %d to delete",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
- return OK;
-}
-
-status_t Camera2Device::deleteReprocessStream(int id) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
- streamI != mReprocessStreams.end(); streamI++) {
- if ((*streamI)->getId() == id) {
- status_t res = (*streamI)->release();
- if (res != OK) {
- ALOGE("%s: Unable to release reprocess stream %d from "
- "HAL device: %s (%d)", __FUNCTION__, id,
- strerror(-res), res);
- return res;
- }
- mReprocessStreams.erase(streamI);
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Unable to find stream %d to delete",
- __FUNCTION__, mId, id);
- return BAD_VALUE;
- }
- return OK;
-}
-
-status_t Camera2Device::configureStreams(bool isConstrainedHighSpeed) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
-
- /**
- * HAL2 devices do not need to configure streams;
- * streams are created on the fly.
- */
- ALOGW("%s: No-op for HAL2 devices", __FUNCTION__);
-
- return OK;
-}
-
-
-status_t Camera2Device::createDefaultRequest(int templateId,
- CameraMetadata *request) {
- ATRACE_CALL();
- status_t err;
- ALOGV("%s: E", __FUNCTION__);
- camera_metadata_t *rawRequest;
- err = mHal2Device->ops->construct_default_request(
- mHal2Device, templateId, &rawRequest);
- request->acquire(rawRequest);
- return err;
-}
-
-status_t Camera2Device::waitUntilDrained() {
- ATRACE_CALL();
- static const uint32_t kSleepTime = 50000; // 50 ms
- static const uint32_t kMaxSleepTime = 10000000; // 10 s
- ALOGV("%s: Camera %d: Starting wait", __FUNCTION__, mId);
- if (mRequestQueue.getBufferCount() ==
- CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS) return INVALID_OPERATION;
-
- // TODO: Set up notifications from HAL, instead of sleeping here
- uint32_t totalTime = 0;
- while (mHal2Device->ops->get_in_progress_count(mHal2Device) > 0) {
- usleep(kSleepTime);
- totalTime += kSleepTime;
- if (totalTime > kMaxSleepTime) {
- ALOGE("%s: Waited %d us, %d requests still in flight", __FUNCTION__,
- totalTime, mHal2Device->ops->get_in_progress_count(mHal2Device));
- return TIMED_OUT;
- }
- }
- ALOGV("%s: Camera %d: HAL is idle", __FUNCTION__, mId);
- return OK;
-}
-
-status_t Camera2Device::setNotifyCallback(NotificationListener *listener) {
- ATRACE_CALL();
- status_t res;
- res = mHal2Device->ops->set_notify_callback(mHal2Device, notificationCallback,
- reinterpret_cast<void*>(listener) );
- if (res != OK) {
- ALOGE("%s: Unable to set notification callback!", __FUNCTION__);
- }
- return res;
-}
-
-bool Camera2Device::willNotify3A() {
- return true;
-}
-
-void Camera2Device::notificationCallback(int32_t msg_type,
- int32_t ext1,
- int32_t ext2,
- int32_t ext3,
- void *user) {
- ATRACE_CALL();
- NotificationListener *listener = reinterpret_cast<NotificationListener*>(user);
- ALOGV("%s: Notification %d, arguments %d, %d, %d", __FUNCTION__, msg_type,
- ext1, ext2, ext3);
- if (listener != NULL) {
- switch (msg_type) {
- case CAMERA2_MSG_ERROR:
- // TODO: This needs to be fixed. ext2 and ext3 need to be considered.
- listener->notifyError(
- ((ext1 == CAMERA2_MSG_ERROR_DEVICE)
- || (ext1 == CAMERA2_MSG_ERROR_HARDWARE)) ?
- ICameraDeviceCallbacks::ERROR_CAMERA_DEVICE :
- ICameraDeviceCallbacks::ERROR_CAMERA_SERVICE,
- CaptureResultExtras());
- break;
- case CAMERA2_MSG_SHUTTER: {
- // TODO: Only needed for camera2 API, which is unsupported
- // by HAL2 directly.
- // nsecs_t timestamp = (nsecs_t)ext2 | ((nsecs_t)(ext3) << 32 );
- // listener->notifyShutter(requestId, timestamp);
- break;
- }
- case CAMERA2_MSG_AUTOFOCUS:
- listener->notifyAutoFocus(ext1, ext2);
- break;
- case CAMERA2_MSG_AUTOEXPOSURE:
- listener->notifyAutoExposure(ext1, ext2);
- break;
- case CAMERA2_MSG_AUTOWB:
- listener->notifyAutoWhitebalance(ext1, ext2);
- break;
- default:
- ALOGE("%s: Unknown notification %d (arguments %d, %d, %d)!",
- __FUNCTION__, msg_type, ext1, ext2, ext3);
- }
- }
-}
-
-status_t Camera2Device::waitForNextFrame(nsecs_t timeout) {
- return mFrameQueue.waitForBuffer(timeout);
-}
-
-status_t Camera2Device::getNextResult(CaptureResult *result) {
- ATRACE_CALL();
- ALOGV("%s: get CaptureResult", __FUNCTION__);
- if (result == NULL) {
- ALOGE("%s: result pointer is NULL", __FUNCTION__);
- return BAD_VALUE;
- }
- status_t res;
- camera_metadata_t *rawFrame;
- res = mFrameQueue.dequeue(&rawFrame);
- if (rawFrame == NULL) {
- return NOT_ENOUGH_DATA;
- } else if (res == OK) {
- result->mMetadata.acquire(rawFrame);
- }
-
- return res;
-}
-
-status_t Camera2Device::triggerAutofocus(uint32_t id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Triggering autofocus, id %d", __FUNCTION__, id);
- res = mHal2Device->ops->trigger_action(mHal2Device,
- CAMERA2_TRIGGER_AUTOFOCUS, id, 0);
- if (res != OK) {
- ALOGE("%s: Error triggering autofocus (id %d)",
- __FUNCTION__, id);
- }
- return res;
-}
-
-status_t Camera2Device::triggerCancelAutofocus(uint32_t id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Canceling autofocus, id %d", __FUNCTION__, id);
- res = mHal2Device->ops->trigger_action(mHal2Device,
- CAMERA2_TRIGGER_CANCEL_AUTOFOCUS, id, 0);
- if (res != OK) {
- ALOGE("%s: Error canceling autofocus (id %d)",
- __FUNCTION__, id);
- }
- return res;
-}
-
-status_t Camera2Device::triggerPrecaptureMetering(uint32_t id) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Triggering precapture metering, id %d", __FUNCTION__, id);
- res = mHal2Device->ops->trigger_action(mHal2Device,
- CAMERA2_TRIGGER_PRECAPTURE_METERING, id, 0);
- if (res != OK) {
- ALOGE("%s: Error triggering precapture metering (id %d)",
- __FUNCTION__, id);
- }
- return res;
-}
-
-status_t Camera2Device::pushReprocessBuffer(int reprocessStreamId,
- buffer_handle_t *buffer, wp<BufferReleasedListener> listener) {
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- bool found = false;
- status_t res = OK;
- for (ReprocessStreamList::iterator streamI = mReprocessStreams.begin();
- streamI != mReprocessStreams.end(); streamI++) {
- if ((*streamI)->getId() == reprocessStreamId) {
- res = (*streamI)->pushIntoStream(buffer, listener);
- if (res != OK) {
- ALOGE("%s: Unable to push buffer to reprocess stream %d: %s (%d)",
- __FUNCTION__, reprocessStreamId, strerror(-res), res);
- return res;
- }
- found = true;
- break;
- }
- }
- if (!found) {
- ALOGE("%s: Camera %d: Unable to find reprocess stream %d",
- __FUNCTION__, mId, reprocessStreamId);
- res = BAD_VALUE;
- }
- return res;
-}
-
-status_t Camera2Device::flush(int64_t* /*lastFrameNumber*/) {
- ATRACE_CALL();
-
- mRequestQueue.clear();
- return waitUntilDrained();
-}
-
-status_t Camera2Device::prepare(int streamId) {
- ATRACE_CALL();
- ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
- return NO_INIT;
-}
-
-status_t Camera2Device::tearDown(int streamId) {
- ATRACE_CALL();
- ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
- return NO_INIT;
-}
-
-status_t Camera2Device::prepare(int maxCount, int streamId) {
- ATRACE_CALL();
- ALOGE("%s: Camera %d: unimplemented", __FUNCTION__, mId);
- return NO_INIT;
-}
-
-uint32_t Camera2Device::getDeviceVersion() {
- ATRACE_CALL();
- return mDeviceVersion;
-}
-
-/**
- * Camera2Device::MetadataQueue
- */
-
-Camera2Device::MetadataQueue::MetadataQueue():
- mHal2Device(NULL),
- mFrameCount(0),
- mLatestRequestId(0),
- mCount(0),
- mStreamSlotCount(0),
- mSignalConsumer(true)
-{
- ATRACE_CALL();
- camera2_request_queue_src_ops::dequeue_request = consumer_dequeue;
- camera2_request_queue_src_ops::request_count = consumer_buffer_count;
- camera2_request_queue_src_ops::free_request = consumer_free;
-
- camera2_frame_queue_dst_ops::dequeue_frame = producer_dequeue;
- camera2_frame_queue_dst_ops::cancel_frame = producer_cancel;
- camera2_frame_queue_dst_ops::enqueue_frame = producer_enqueue;
-}
-
-Camera2Device::MetadataQueue::~MetadataQueue() {
- ATRACE_CALL();
- clear();
-}
-
-// Connect to camera2 HAL as consumer (input requests/reprocessing)
-status_t Camera2Device::MetadataQueue::setConsumerDevice(camera2_device_t *d) {
- ATRACE_CALL();
- status_t res;
- res = d->ops->set_request_queue_src_ops(d,
- this);
- if (res != OK) return res;
- mHal2Device = d;
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::setProducerDevice(camera2_device_t *d) {
- ATRACE_CALL();
- status_t res;
- res = d->ops->set_frame_queue_dst_ops(d,
- this);
- return res;
-}
-
-// Real interfaces
-status_t Camera2Device::MetadataQueue::enqueue(camera_metadata_t *buf) {
- ATRACE_CALL();
- ALOGVV("%s: E", __FUNCTION__);
- Mutex::Autolock l(mMutex);
-
- mCount++;
- mEntries.push_back(buf);
-
- return signalConsumerLocked();
-}
-
-int Camera2Device::MetadataQueue::getBufferCount() {
- ATRACE_CALL();
- Mutex::Autolock l(mMutex);
- if (mStreamSlotCount > 0) {
- return CAMERA2_REQUEST_QUEUE_IS_BOTTOMLESS;
- }
- return mCount;
-}
-
-status_t Camera2Device::MetadataQueue::dequeue(camera_metadata_t **buf,
- bool incrementCount)
-{
- ATRACE_CALL();
- ALOGVV("%s: E", __FUNCTION__);
- status_t res;
- Mutex::Autolock l(mMutex);
-
- if (mCount == 0) {
- if (mStreamSlotCount == 0) {
- ALOGVV("%s: Empty", __FUNCTION__);
- *buf = NULL;
- mSignalConsumer = true;
- return OK;
- }
- ALOGVV("%s: Streaming %d frames to queue", __FUNCTION__,
- mStreamSlotCount);
-
- for (List<camera_metadata_t*>::iterator slotEntry = mStreamSlot.begin();
- slotEntry != mStreamSlot.end();
- slotEntry++ ) {
- size_t entries = get_camera_metadata_entry_count(*slotEntry);
- size_t dataBytes = get_camera_metadata_data_count(*slotEntry);
-
- camera_metadata_t *copy =
- allocate_camera_metadata(entries, dataBytes);
- append_camera_metadata(copy, *slotEntry);
- mEntries.push_back(copy);
- }
- mCount = mStreamSlotCount;
- }
- ALOGVV("MetadataQueue: deque (%d buffers)", mCount);
- camera_metadata_t *b = *(mEntries.begin());
- mEntries.erase(mEntries.begin());
-
- if (incrementCount) {
- ATRACE_INT("cam2_request", mFrameCount);
- camera_metadata_entry_t frameCount;
- res = find_camera_metadata_entry(b,
- ANDROID_REQUEST_FRAME_COUNT,
- &frameCount);
- if (res != OK) {
- ALOGE("%s: Unable to add frame count: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- } else {
- *frameCount.data.i32 = mFrameCount;
- }
- mFrameCount++;
- }
-
- // Check for request ID, and if present, signal waiters.
- camera_metadata_entry_t requestId;
- res = find_camera_metadata_entry(b,
- ANDROID_REQUEST_ID,
- &requestId);
- if (res == OK) {
- mLatestRequestId = requestId.data.i32[0];
- mNewRequestId.signal();
- }
-
- *buf = b;
- mCount--;
-
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::waitForBuffer(nsecs_t timeout)
-{
- Mutex::Autolock l(mMutex);
- status_t res;
- while (mCount == 0) {
- res = notEmpty.waitRelative(mMutex,timeout);
- if (res != OK) return res;
- }
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::waitForDequeue(int32_t id,
- nsecs_t timeout) {
- Mutex::Autolock l(mMutex);
- status_t res;
- while (mLatestRequestId != id) {
- nsecs_t startTime = systemTime();
-
- res = mNewRequestId.waitRelative(mMutex, timeout);
- if (res != OK) return res;
-
- timeout -= (systemTime() - startTime);
- }
-
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::setStreamSlot(camera_metadata_t *buf)
-{
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- Mutex::Autolock l(mMutex);
- if (buf == NULL) {
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
- mStreamSlotCount = 0;
- return OK;
- }
-
- if (mStreamSlotCount > 1) {
- List<camera_metadata_t*>::iterator deleter = ++mStreamSlot.begin();
- freeBuffers(++mStreamSlot.begin(), mStreamSlot.end());
- mStreamSlotCount = 1;
- }
- if (mStreamSlotCount == 1) {
- free_camera_metadata( *(mStreamSlot.begin()) );
- *(mStreamSlot.begin()) = buf;
- } else {
- mStreamSlot.push_front(buf);
- mStreamSlotCount = 1;
- }
- return signalConsumerLocked();
-}
-
-status_t Camera2Device::MetadataQueue::setStreamSlot(
- const List<camera_metadata_t*> &bufs)
-{
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
- Mutex::Autolock l(mMutex);
-
- if (mStreamSlotCount > 0) {
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
- }
- mStreamSlotCount = 0;
- for (List<camera_metadata_t*>::const_iterator r = bufs.begin();
- r != bufs.end(); r++) {
- mStreamSlot.push_back(*r);
- mStreamSlotCount++;
- }
- return signalConsumerLocked();
-}
-
-status_t Camera2Device::MetadataQueue::clear()
-{
- ATRACE_CALL();
- ALOGV("%s: E", __FUNCTION__);
-
- Mutex::Autolock l(mMutex);
-
- // Clear streaming slot
- freeBuffers(mStreamSlot.begin(), mStreamSlot.end());
- mStreamSlotCount = 0;
-
- // Clear request queue
- freeBuffers(mEntries.begin(), mEntries.end());
- mCount = 0;
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::dump(int fd,
- const Vector<String16>& /*args*/) {
- ATRACE_CALL();
- String8 result;
- status_t notLocked;
- notLocked = mMutex.tryLock();
- if (notLocked) {
- result.append(" (Unable to lock queue mutex)\n");
- }
- result.appendFormat(" Current frame number: %d\n", mFrameCount);
- if (mStreamSlotCount == 0) {
- result.append(" Stream slot: Empty\n");
- write(fd, result.string(), result.size());
- } else {
- result.appendFormat(" Stream slot: %zu entries\n",
- mStreamSlot.size());
- int i = 0;
- for (List<camera_metadata_t*>::iterator r = mStreamSlot.begin();
- r != mStreamSlot.end(); r++) {
- result = String8::format(" Stream slot buffer %d:\n", i);
- write(fd, result.string(), result.size());
- dump_indented_camera_metadata(*r, fd, 2, 10);
- i++;
- }
- }
- if (mEntries.size() == 0) {
- result = " Main queue is empty\n";
- write(fd, result.string(), result.size());
- } else {
- result = String8::format(" Main queue has %zu entries:\n",
- mEntries.size());
- int i = 0;
- for (List<camera_metadata_t*>::iterator r = mEntries.begin();
- r != mEntries.end(); r++) {
- result = String8::format(" Queue entry %d:\n", i);
- write(fd, result.string(), result.size());
- dump_indented_camera_metadata(*r, fd, 2, 10);
- i++;
- }
- }
-
- if (notLocked == 0) {
- mMutex.unlock();
- }
-
- return OK;
-}
-
-status_t Camera2Device::MetadataQueue::signalConsumerLocked() {
- ATRACE_CALL();
- status_t res = OK;
- notEmpty.signal();
- if (mSignalConsumer && mHal2Device != NULL) {
- mSignalConsumer = false;
-
- mMutex.unlock();
- ALOGV("%s: Signaling consumer", __FUNCTION__);
- res = mHal2Device->ops->notify_request_queue_not_empty(mHal2Device);
- mMutex.lock();
- }
- return res;
-}
-
-status_t Camera2Device::MetadataQueue::freeBuffers(
- List<camera_metadata_t*>::iterator start,
- List<camera_metadata_t*>::iterator end)
-{
- ATRACE_CALL();
- while (start != end) {
- free_camera_metadata(*start);
- start = mStreamSlot.erase(start);
- }
- return OK;
-}
-
-Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
- const camera2_request_queue_src_ops_t *q)
-{
- const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
- return const_cast<MetadataQueue*>(cmq);
-}
-
-Camera2Device::MetadataQueue* Camera2Device::MetadataQueue::getInstance(
- const camera2_frame_queue_dst_ops_t *q)
-{
- const MetadataQueue* cmq = static_cast<const MetadataQueue*>(q);
- return const_cast<MetadataQueue*>(cmq);
-}
-
-int Camera2Device::MetadataQueue::consumer_buffer_count(
- const camera2_request_queue_src_ops_t *q)
-{
- MetadataQueue *queue = getInstance(q);
- return queue->getBufferCount();
-}
-
-int Camera2Device::MetadataQueue::consumer_dequeue(
- const camera2_request_queue_src_ops_t *q,
- camera_metadata_t **buffer)
-{
- MetadataQueue *queue = getInstance(q);
- return queue->dequeue(buffer, true);
-}
-
-int Camera2Device::MetadataQueue::consumer_free(
- const camera2_request_queue_src_ops_t *q,
- camera_metadata_t *old_buffer)
-{
- ATRACE_CALL();
- MetadataQueue *queue = getInstance(q);
- (void)queue;
- free_camera_metadata(old_buffer);
- return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_dequeue(
- const camera2_frame_queue_dst_ops_t * /*q*/,
- size_t entries, size_t bytes,
- camera_metadata_t **buffer)
-{
- ATRACE_CALL();
- camera_metadata_t *new_buffer =
- allocate_camera_metadata(entries, bytes);
- if (new_buffer == NULL) return NO_MEMORY;
- *buffer = new_buffer;
- return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_cancel(
- const camera2_frame_queue_dst_ops_t * /*q*/,
- camera_metadata_t *old_buffer)
-{
- ATRACE_CALL();
- free_camera_metadata(old_buffer);
- return OK;
-}
-
-int Camera2Device::MetadataQueue::producer_enqueue(
- const camera2_frame_queue_dst_ops_t *q,
- camera_metadata_t *filled_buffer)
-{
- MetadataQueue *queue = getInstance(q);
- return queue->enqueue(filled_buffer);
-}
-
-/**
- * Camera2Device::StreamAdapter
- */
-
-#ifndef container_of
-#define container_of(ptr, type, member) \
- (type *)((char*)(ptr) - offsetof(type, member))
-#endif
-
-Camera2Device::StreamAdapter::StreamAdapter(camera2_device_t *d):
- mState(RELEASED),
- mHal2Device(d),
- mId(-1),
- mWidth(0), mHeight(0), mFormat(0), mSize(0), mUsage(0),
- mMaxProducerBuffers(0), mMaxConsumerBuffers(0),
- mTotalBuffers(0),
- mFormatRequested(0),
- mActiveBuffers(0),
- mFrameCount(0),
- mLastTimestamp(0)
-{
- camera2_stream_ops::dequeue_buffer = dequeue_buffer;
- camera2_stream_ops::enqueue_buffer = enqueue_buffer;
- camera2_stream_ops::cancel_buffer = cancel_buffer;
- camera2_stream_ops::set_crop = set_crop;
-}
-
-Camera2Device::StreamAdapter::~StreamAdapter() {
- ATRACE_CALL();
- if (mState != RELEASED) {
- release();
- }
-}
-
-status_t Camera2Device::StreamAdapter::connectToDevice(
- sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- if (mState != RELEASED) return INVALID_OPERATION;
- if (consumer == NULL) {
- ALOGE("%s: Null consumer passed to stream adapter", __FUNCTION__);
- return BAD_VALUE;
- }
-
- ALOGV("%s: New stream parameters %d x %d, format 0x%x, size %zu",
- __FUNCTION__, width, height, format, size);
-
- mConsumerInterface = consumer;
- mWidth = width;
- mHeight = height;
- mSize = (format == HAL_PIXEL_FORMAT_BLOB) ? size : 0;
- mFormatRequested = format;
-
- // Allocate device-side stream interface
-
- uint32_t id;
- uint32_t formatActual;
- uint32_t usage;
- uint32_t maxBuffers = 2;
- res = mHal2Device->ops->allocate_stream(mHal2Device,
- mWidth, mHeight, mFormatRequested, getStreamOps(),
- &id, &formatActual, &usage, &maxBuffers);
- if (res != OK) {
- ALOGE("%s: Device stream allocation failed: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- ALOGV("%s: Allocated stream id %d, actual format 0x%x, "
- "usage 0x%x, producer wants %d buffers", __FUNCTION__,
- id, formatActual, usage, maxBuffers);
-
- mId = id;
- mFormat = formatActual;
- mUsage = usage;
- mMaxProducerBuffers = maxBuffers;
-
- mState = ALLOCATED;
-
- // Configure consumer-side ANativeWindow interface
- res = native_window_api_connect(mConsumerInterface.get(),
- NATIVE_WINDOW_API_CAMERA);
- if (res != OK) {
- ALOGE("%s: Unable to connect to native window for stream %d",
- __FUNCTION__, mId);
-
- return res;
- }
-
- mState = CONNECTED;
-
- res = native_window_set_usage(mConsumerInterface.get(), mUsage);
- if (res != OK) {
- ALOGE("%s: Unable to configure usage %08x for stream %d",
- __FUNCTION__, mUsage, mId);
- return res;
- }
-
- res = native_window_set_scaling_mode(mConsumerInterface.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream scaling: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- res = setTransform(0);
- if (res != OK) {
- return res;
- }
-
- if (mFormat == HAL_PIXEL_FORMAT_BLOB) {
- res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
- mSize, 1);
- if (res != OK) {
- ALOGE("%s: Unable to configure compressed stream buffer dimensions"
- " %d x %d, size %zu for stream %d",
- __FUNCTION__, mWidth, mHeight, mSize, mId);
- return res;
- }
- } else {
- res = native_window_set_buffers_dimensions(mConsumerInterface.get(),
- mWidth, mHeight);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream buffer dimensions"
- " %d x %d for stream %d",
- __FUNCTION__, mWidth, mHeight, mId);
- return res;
- }
- }
-
- res = native_window_set_buffers_format(mConsumerInterface.get(), mFormat);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream buffer format"
- " %#x for stream %d",
- __FUNCTION__, mFormat, mId);
- return res;
- }
-
- int maxConsumerBuffers;
- res = mConsumerInterface->query(mConsumerInterface.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &maxConsumerBuffers);
- if (res != OK) {
- ALOGE("%s: Unable to query consumer undequeued"
- " buffer count for stream %d", __FUNCTION__, mId);
- return res;
- }
- mMaxConsumerBuffers = maxConsumerBuffers;
-
- ALOGV("%s: Consumer wants %d buffers", __FUNCTION__,
- mMaxConsumerBuffers);
-
- mTotalBuffers = mMaxConsumerBuffers + mMaxProducerBuffers;
- mActiveBuffers = 0;
- mFrameCount = 0;
- mLastTimestamp = 0;
-
- res = native_window_set_buffer_count(mConsumerInterface.get(),
- mTotalBuffers);
- if (res != OK) {
- ALOGE("%s: Unable to set buffer count for stream %d",
- __FUNCTION__, mId);
- return res;
- }
-
- // Register allocated buffers with HAL device
- buffer_handle_t *buffers = new buffer_handle_t[mTotalBuffers];
- ANativeWindowBuffer **anwBuffers = new ANativeWindowBuffer*[mTotalBuffers];
- uint32_t bufferIdx = 0;
- for (; bufferIdx < mTotalBuffers; bufferIdx++) {
- res = native_window_dequeue_buffer_and_wait(mConsumerInterface.get(),
- &anwBuffers[bufferIdx]);
- if (res != OK) {
- ALOGE("%s: Unable to dequeue buffer %d for initial registration for "
- "stream %d", __FUNCTION__, bufferIdx, mId);
- goto cleanUpBuffers;
- }
-
- buffers[bufferIdx] = anwBuffers[bufferIdx]->handle;
- ALOGV("%s: Buffer %p allocated", __FUNCTION__, (void*)buffers[bufferIdx]);
- }
-
- ALOGV("%s: Registering %d buffers with camera HAL", __FUNCTION__, mTotalBuffers);
- res = mHal2Device->ops->register_stream_buffers(mHal2Device,
- mId,
- mTotalBuffers,
- buffers);
- if (res != OK) {
- ALOGE("%s: Unable to register buffers with HAL device for stream %d",
- __FUNCTION__, mId);
- } else {
- mState = ACTIVE;
- }
-
-cleanUpBuffers:
- ALOGV("%s: Cleaning up %d buffers", __FUNCTION__, bufferIdx);
- for (uint32_t i = 0; i < bufferIdx; i++) {
- res = mConsumerInterface->cancelBuffer(mConsumerInterface.get(),
- anwBuffers[i], -1);
- if (res != OK) {
- ALOGE("%s: Unable to cancel buffer %d after registration",
- __FUNCTION__, i);
- }
- }
- delete[] anwBuffers;
- delete[] buffers;
-
- return res;
-}
-
-status_t Camera2Device::StreamAdapter::release() {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Releasing stream %d (%d x %d, format %d)", __FUNCTION__, mId,
- mWidth, mHeight, mFormat);
- if (mState >= ALLOCATED) {
- res = mHal2Device->ops->release_stream(mHal2Device, mId);
- if (res != OK) {
- ALOGE("%s: Unable to release stream %d",
- __FUNCTION__, mId);
- return res;
- }
- }
- if (mState >= CONNECTED) {
- res = native_window_api_disconnect(mConsumerInterface.get(),
- NATIVE_WINDOW_API_CAMERA);
-
- /* this is not an error. if client calling process dies,
- the window will also die and all calls to it will return
- DEAD_OBJECT, thus it's already "disconnected" */
- if (res == DEAD_OBJECT) {
- ALOGW("%s: While disconnecting stream %d from native window, the"
- " native window died from under us", __FUNCTION__, mId);
- }
- else if (res != OK) {
- ALOGE("%s: Unable to disconnect stream %d from native window (error %d %s)",
- __FUNCTION__, mId, res, strerror(-res));
- return res;
- }
- }
- mId = -1;
- mState = RELEASED;
- return OK;
-}
-
-status_t Camera2Device::StreamAdapter::setTransform(int transform) {
- ATRACE_CALL();
- status_t res;
- if (mState < CONNECTED) {
- ALOGE("%s: Cannot set transform on unconnected stream", __FUNCTION__);
- return INVALID_OPERATION;
- }
- res = native_window_set_buffers_transform(mConsumerInterface.get(),
- transform);
- if (res != OK) {
- ALOGE("%s: Unable to configure stream transform to %x: %s (%d)",
- __FUNCTION__, transform, strerror(-res), res);
- }
- return res;
-}
-
-status_t Camera2Device::StreamAdapter::dump(int fd,
- const Vector<String16>& /*args*/) {
- ATRACE_CALL();
- String8 result = String8::format(" Stream %d: %d x %d, format 0x%x\n",
- mId, mWidth, mHeight, mFormat);
- result.appendFormat(" size %zu, usage 0x%x, requested format 0x%x\n",
- mSize, mUsage, mFormatRequested);
- result.appendFormat(" total buffers: %d, dequeued buffers: %d\n",
- mTotalBuffers, mActiveBuffers);
- result.appendFormat(" frame count: %d, last timestamp %" PRId64 "\n",
- mFrameCount, mLastTimestamp);
- write(fd, result.string(), result.size());
- return OK;
-}
-
-const camera2_stream_ops *Camera2Device::StreamAdapter::getStreamOps() {
- return static_cast<camera2_stream_ops *>(this);
-}
-
-ANativeWindow* Camera2Device::StreamAdapter::toANW(
- const camera2_stream_ops_t *w) {
- return static_cast<const StreamAdapter*>(w)->mConsumerInterface.get();
-}
-
-int Camera2Device::StreamAdapter::dequeue_buffer(const camera2_stream_ops_t *w,
- buffer_handle_t** buffer) {
- ATRACE_CALL();
- int res;
- StreamAdapter* stream =
- const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
- if (stream->mState != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
- return INVALID_OPERATION;
- }
-
- ANativeWindow *a = toANW(w);
- ANativeWindowBuffer* anb;
- res = native_window_dequeue_buffer_and_wait(a, &anb);
- if (res != OK) {
- ALOGE("Stream %d dequeue: Error from native_window: %s (%d)", stream->mId,
- strerror(-res), res);
- return res;
- }
-
- *buffer = &(anb->handle);
- stream->mActiveBuffers++;
-
- ALOGVV("Stream %d dequeue: Buffer %p dequeued", stream->mId, (void*)(**buffer));
- return res;
-}
-
-int Camera2Device::StreamAdapter::enqueue_buffer(const camera2_stream_ops_t* w,
- int64_t timestamp,
- buffer_handle_t* buffer) {
- ATRACE_CALL();
- StreamAdapter *stream =
- const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
- stream->mFrameCount++;
- ALOGVV("Stream %d enqueue: Frame %d (%p) captured at %lld ns",
- stream->mId, stream->mFrameCount, (void*)(*buffer), timestamp);
- int state = stream->mState;
- if (state != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
- return INVALID_OPERATION;
- }
- ANativeWindow *a = toANW(w);
- status_t err;
-
- err = native_window_set_buffers_timestamp(a, timestamp);
- if (err != OK) {
- ALOGE("%s: Error setting timestamp on native window: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- return err;
- }
- err = a->queueBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle), -1);
- if (err != OK) {
- ALOGE("%s: Error queueing buffer to native window: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- return err;
- }
-
- stream->mActiveBuffers--;
- stream->mLastTimestamp = timestamp;
- return OK;
-}
-
-int Camera2Device::StreamAdapter::cancel_buffer(const camera2_stream_ops_t* w,
- buffer_handle_t* buffer) {
- ATRACE_CALL();
- StreamAdapter *stream =
- const_cast<StreamAdapter*>(static_cast<const StreamAdapter*>(w));
- ALOGVV("Stream %d cancel: Buffer %p",
- stream->mId, (void*)(*buffer));
- if (stream->mState != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
- return INVALID_OPERATION;
- }
-
- ANativeWindow *a = toANW(w);
- int err = a->cancelBuffer(a,
- container_of(buffer, ANativeWindowBuffer, handle), -1);
- if (err != OK) {
- ALOGE("%s: Error canceling buffer to native window: %s (%d)",
- __FUNCTION__, strerror(-err), err);
- return err;
- }
-
- stream->mActiveBuffers--;
- return OK;
-}
-
-int Camera2Device::StreamAdapter::set_crop(const camera2_stream_ops_t* w,
- int left, int top, int right, int bottom) {
- ATRACE_CALL();
- int state = static_cast<const StreamAdapter*>(w)->mState;
- if (state != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
- return INVALID_OPERATION;
- }
- ANativeWindow *a = toANW(w);
- android_native_rect_t crop = { left, top, right, bottom };
- return native_window_set_crop(a, &crop);
-}
-
-/**
- * Camera2Device::ReprocessStreamAdapter
- */
-
-#ifndef container_of
-#define container_of(ptr, type, member) \
- (type *)((char*)(ptr) - offsetof(type, member))
-#endif
-
-Camera2Device::ReprocessStreamAdapter::ReprocessStreamAdapter(camera2_device_t *d):
- mState(RELEASED),
- mHal2Device(d),
- mId(-1),
- mWidth(0), mHeight(0), mFormat(0),
- mActiveBuffers(0),
- mFrameCount(0)
-{
- ATRACE_CALL();
- camera2_stream_in_ops::acquire_buffer = acquire_buffer;
- camera2_stream_in_ops::release_buffer = release_buffer;
-}
-
-Camera2Device::ReprocessStreamAdapter::~ReprocessStreamAdapter() {
- ATRACE_CALL();
- if (mState != RELEASED) {
- release();
- }
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::connectToDevice(
- const sp<StreamAdapter> &outputStream) {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: E", __FUNCTION__);
-
- if (mState != RELEASED) return INVALID_OPERATION;
- if (outputStream == NULL) {
- ALOGE("%s: Null base stream passed to reprocess stream adapter",
- __FUNCTION__);
- return BAD_VALUE;
- }
-
- mBaseStream = outputStream;
- mWidth = outputStream->getWidth();
- mHeight = outputStream->getHeight();
- mFormat = outputStream->getFormat();
-
- ALOGV("%s: New reprocess stream parameters %d x %d, format 0x%x",
- __FUNCTION__, mWidth, mHeight, mFormat);
-
- // Allocate device-side stream interface
-
- uint32_t id;
- res = mHal2Device->ops->allocate_reprocess_stream_from_stream(mHal2Device,
- outputStream->getId(), getStreamOps(),
- &id);
- if (res != OK) {
- ALOGE("%s: Device reprocess stream allocation failed: %s (%d)",
- __FUNCTION__, strerror(-res), res);
- return res;
- }
-
- ALOGV("%s: Allocated reprocess stream id %d based on stream %d",
- __FUNCTION__, id, outputStream->getId());
-
- mId = id;
-
- mState = ACTIVE;
-
- return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::release() {
- ATRACE_CALL();
- status_t res;
- ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
- if (mState >= ACTIVE) {
- res = mHal2Device->ops->release_reprocess_stream(mHal2Device, mId);
- if (res != OK) {
- ALOGE("%s: Unable to release stream %d",
- __FUNCTION__, mId);
- return res;
- }
- }
-
- List<QueueEntry>::iterator s;
- for (s = mQueue.begin(); s != mQueue.end(); s++) {
- sp<BufferReleasedListener> listener = s->releaseListener.promote();
- if (listener != 0) listener->onBufferReleased(s->handle);
- }
- for (s = mInFlightQueue.begin(); s != mInFlightQueue.end(); s++) {
- sp<BufferReleasedListener> listener = s->releaseListener.promote();
- if (listener != 0) listener->onBufferReleased(s->handle);
- }
- mQueue.clear();
- mInFlightQueue.clear();
-
- mState = RELEASED;
- return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::pushIntoStream(
- buffer_handle_t *handle, const wp<BufferReleasedListener> &releaseListener) {
- ATRACE_CALL();
- // TODO: Some error checking here would be nice
- ALOGV("%s: Pushing buffer %p to stream", __FUNCTION__, (void*)(*handle));
-
- QueueEntry entry;
- entry.handle = handle;
- entry.releaseListener = releaseListener;
- mQueue.push_back(entry);
- return OK;
-}
-
-status_t Camera2Device::ReprocessStreamAdapter::dump(int fd,
- const Vector<String16>& /*args*/) {
- ATRACE_CALL();
- String8 result =
- String8::format(" Reprocess stream %d: %d x %d, fmt 0x%x\n",
- mId, mWidth, mHeight, mFormat);
- result.appendFormat(" acquired buffers: %d\n",
- mActiveBuffers);
- result.appendFormat(" frame count: %d\n",
- mFrameCount);
- write(fd, result.string(), result.size());
- return OK;
-}
-
-const camera2_stream_in_ops *Camera2Device::ReprocessStreamAdapter::getStreamOps() {
- return static_cast<camera2_stream_in_ops *>(this);
-}
-
-int Camera2Device::ReprocessStreamAdapter::acquire_buffer(
- const camera2_stream_in_ops_t *w,
- buffer_handle_t** buffer) {
- ATRACE_CALL();
-
- ReprocessStreamAdapter* stream =
- const_cast<ReprocessStreamAdapter*>(
- static_cast<const ReprocessStreamAdapter*>(w));
- if (stream->mState != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, stream->mState);
- return INVALID_OPERATION;
- }
-
- if (stream->mQueue.empty()) {
- *buffer = NULL;
- return OK;
- }
-
- QueueEntry &entry = *(stream->mQueue.begin());
-
- *buffer = entry.handle;
-
- stream->mInFlightQueue.push_back(entry);
- stream->mQueue.erase(stream->mQueue.begin());
-
- stream->mActiveBuffers++;
-
- ALOGV("Stream %d acquire: Buffer %p acquired", stream->mId,
- (void*)(**buffer));
- return OK;
-}
-
-int Camera2Device::ReprocessStreamAdapter::release_buffer(
- const camera2_stream_in_ops_t* w,
- buffer_handle_t* buffer) {
- ATRACE_CALL();
- ReprocessStreamAdapter *stream =
- const_cast<ReprocessStreamAdapter*>(
- static_cast<const ReprocessStreamAdapter*>(w) );
- stream->mFrameCount++;
- ALOGV("Reprocess stream %d release: Frame %d (%p)",
- stream->mId, stream->mFrameCount, (void*)*buffer);
- int state = stream->mState;
- if (state != ACTIVE) {
- ALOGE("%s: Called when in bad state: %d", __FUNCTION__, state);
- return INVALID_OPERATION;
- }
- stream->mActiveBuffers--;
-
- List<QueueEntry>::iterator s;
- for (s = stream->mInFlightQueue.begin(); s != stream->mInFlightQueue.end(); s++) {
- if ( s->handle == buffer ) break;
- }
- if (s == stream->mInFlightQueue.end()) {
- ALOGE("%s: Can't find buffer %p in in-flight list!", __FUNCTION__,
- buffer);
- return INVALID_OPERATION;
- }
-
- sp<BufferReleasedListener> listener = s->releaseListener.promote();
- if (listener != 0) {
- listener->onBufferReleased(s->handle);
- } else {
- ALOGE("%s: Can't free buffer - missing listener", __FUNCTION__);
- }
- stream->mInFlightQueue.erase(s);
-
- return OK;
-}
-
-// camera 2 devices don't support reprocessing
-status_t Camera2Device::createInputStream(
- uint32_t width, uint32_t height, int format, int *id) {
- ALOGE("%s: camera 2 devices don't support reprocessing", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-// camera 2 devices don't support reprocessing
-status_t Camera2Device::getInputBufferProducer(
- sp<IGraphicBufferProducer> *producer) {
- ALOGE("%s: camera 2 devices don't support reprocessing", __FUNCTION__);
- return INVALID_OPERATION;
-}
-
-}; // namespace android
diff --git a/services/camera/libcameraservice/device2/Camera2Device.h b/services/camera/libcameraservice/device2/Camera2Device.h
deleted file mode 100644
index b4d343c..0000000
--- a/services/camera/libcameraservice/device2/Camera2Device.h
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
-#define ANDROID_SERVERS_CAMERA_CAMERA2DEVICE_H
-
-#include <utils/Condition.h>
-#include <utils/Errors.h>
-#include <utils/List.h>
-#include <utils/Mutex.h>
-
-#include "common/CameraDeviceBase.h"
-
-namespace android {
-
-/**
- * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_2_0
- *
- * TODO for camera2 API implementation:
- * Does not produce notifyShutter / notifyIdle callbacks to NotificationListener
- * Use waitUntilDrained for idle.
- */
-class Camera2Device: public CameraDeviceBase {
- public:
- Camera2Device(int id);
-
- virtual ~Camera2Device();
-
- /**
- * CameraDevice interface
- */
- virtual int getId() const;
- virtual status_t initialize(CameraModule *module);
- virtual status_t disconnect();
- virtual status_t dump(int fd, const Vector<String16>& args);
- virtual const CameraMetadata& info() const;
- virtual status_t capture(CameraMetadata &request, int64_t *lastFrameNumber = NULL);
- virtual status_t captureList(const List<const CameraMetadata> &requests,
- int64_t *lastFrameNumber = NULL);
- virtual status_t setStreamingRequest(const CameraMetadata &request,
- int64_t *lastFrameNumber = NULL);
- virtual status_t setStreamingRequestList(const List<const CameraMetadata> &requests,
- int64_t *lastFrameNumber = NULL);
- virtual status_t clearStreamingRequest(int64_t *lastFrameNumber = NULL);
- virtual status_t waitUntilRequestReceived(int32_t requestId, nsecs_t timeout);
- virtual status_t createStream(sp<Surface> consumer,
- uint32_t width, uint32_t height, int format,
- android_dataspace dataSpace, camera3_stream_rotation_t rotation, int *id);
- virtual status_t createInputStream(
- uint32_t width, uint32_t height, int format, int *id);
- virtual status_t createReprocessStreamFromStream(int outputId, int *id);
- virtual status_t getStreamInfo(int id,
- uint32_t *width, uint32_t *height,
- uint32_t *format, android_dataspace *dataSpace);
- virtual status_t setStreamTransform(int id, int transform);
- virtual status_t deleteStream(int id);
- virtual status_t deleteReprocessStream(int id);
- // No-op on HAL2 devices
- virtual status_t configureStreams(bool isConstrainedHighSpeed = false);
- virtual status_t getInputBufferProducer(
- sp<IGraphicBufferProducer> *producer);
- virtual status_t createDefaultRequest(int templateId, CameraMetadata *request);
- virtual status_t waitUntilDrained();
- virtual status_t setNotifyCallback(NotificationListener *listener);
- virtual bool willNotify3A();
- virtual status_t waitForNextFrame(nsecs_t timeout);
- virtual status_t getNextResult(CaptureResult *frame);
- virtual status_t triggerAutofocus(uint32_t id);
- virtual status_t triggerCancelAutofocus(uint32_t id);
- virtual status_t triggerPrecaptureMetering(uint32_t id);
- virtual status_t pushReprocessBuffer(int reprocessStreamId,
- buffer_handle_t *buffer, wp<BufferReleasedListener> listener);
- // Flush implemented as just a wait
- virtual status_t flush(int64_t *lastFrameNumber = NULL);
- // Prepare and tearDown are no-ops
- virtual status_t prepare(int streamId);
- virtual status_t tearDown(int streamId);
- virtual status_t prepare(int maxCount, int streamId);
-
- virtual uint32_t getDeviceVersion();
- virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
-
- private:
- const int mId;
- camera2_device_t *mHal2Device;
-
- CameraMetadata mDeviceInfo;
-
- uint32_t mDeviceVersion;
-
- /**
- * Queue class for both sending requests to a camera2 device, and for
- * receiving frames from a camera2 device.
- */
- class MetadataQueue: public camera2_request_queue_src_ops_t,
- public camera2_frame_queue_dst_ops_t {
- public:
- MetadataQueue();
- ~MetadataQueue();
-
- // Interface to camera2 HAL device, either for requests (device is
- // consumer) or for frames (device is producer)
- const camera2_request_queue_src_ops_t* getToConsumerInterface();
- void setFromConsumerInterface(camera2_device_t *d);
-
- // Connect queue consumer endpoint to a camera2 device
- status_t setConsumerDevice(camera2_device_t *d);
- // Connect queue producer endpoint to a camera2 device
- status_t setProducerDevice(camera2_device_t *d);
-
- const camera2_frame_queue_dst_ops_t* getToProducerInterface();
-
- // Real interfaces. On enqueue, queue takes ownership of buffer pointer
- // On dequeue, user takes ownership of buffer pointer.
- status_t enqueue(camera_metadata_t *buf);
- status_t dequeue(camera_metadata_t **buf, bool incrementCount = false);
- int getBufferCount();
- status_t waitForBuffer(nsecs_t timeout);
- // Wait until a buffer with the given ID is dequeued. Will return
- // immediately if the latest buffer dequeued has that ID.
- status_t waitForDequeue(int32_t id, nsecs_t timeout);
-
- // Set repeating buffer(s); if the queue is empty on a dequeue call, the
- // queue copies the contents of the stream slot into the queue, and then
- // dequeues the first new entry. The methods take the ownership of the
- // metadata buffers passed in.
- status_t setStreamSlot(camera_metadata_t *buf);
- status_t setStreamSlot(const List<camera_metadata_t*> &bufs);
-
- // Clear the request queue and the streaming slot
- status_t clear();
-
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- status_t signalConsumerLocked();
- status_t freeBuffers(List<camera_metadata_t*>::iterator start,
- List<camera_metadata_t*>::iterator end);
-
- camera2_device_t *mHal2Device;
-
- Mutex mMutex;
- Condition notEmpty;
-
- int mFrameCount;
- int32_t mLatestRequestId;
- Condition mNewRequestId;
-
- int mCount;
- List<camera_metadata_t*> mEntries;
- int mStreamSlotCount;
- List<camera_metadata_t*> mStreamSlot;
-
- bool mSignalConsumer;
-
- static MetadataQueue* getInstance(
- const camera2_frame_queue_dst_ops_t *q);
- static MetadataQueue* getInstance(
- const camera2_request_queue_src_ops_t *q);
-
- static int consumer_buffer_count(
- const camera2_request_queue_src_ops_t *q);
-
- static int consumer_dequeue(const camera2_request_queue_src_ops_t *q,
- camera_metadata_t **buffer);
-
- static int consumer_free(const camera2_request_queue_src_ops_t *q,
- camera_metadata_t *old_buffer);
-
- static int producer_dequeue(const camera2_frame_queue_dst_ops_t *q,
- size_t entries, size_t bytes,
- camera_metadata_t **buffer);
-
- static int producer_cancel(const camera2_frame_queue_dst_ops_t *q,
- camera_metadata_t *old_buffer);
-
- static int producer_enqueue(const camera2_frame_queue_dst_ops_t *q,
- camera_metadata_t *filled_buffer);
-
- }; // class MetadataQueue
-
- MetadataQueue mRequestQueue;
- MetadataQueue mFrameQueue;
-
- /**
- * Adapter from an ANativeWindow interface to camera2 device stream ops.
- * Also takes care of allocating/deallocating stream in device interface
- */
- class StreamAdapter: public camera2_stream_ops, public virtual RefBase {
- public:
- StreamAdapter(camera2_device_t *d);
-
- ~StreamAdapter();
-
- /**
- * Create a HAL device stream of the requested size and format.
- *
- * If format is CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, then the HAL device
- * selects an appropriate format; it can be queried with getFormat.
- *
- * If format is HAL_PIXEL_FORMAT_COMPRESSED, the size parameter must
- * be equal to the size in bytes of the buffers to allocate for the
- * stream. For other formats, the size parameter is ignored.
- */
- status_t connectToDevice(sp<ANativeWindow> consumer,
- uint32_t width, uint32_t height, int format, size_t size);
-
- status_t release();
-
- status_t setTransform(int transform);
-
- // Get stream parameters.
- // Only valid after a successful connectToDevice call.
- int getId() const { return mId; }
- uint32_t getWidth() const { return mWidth; }
- uint32_t getHeight() const { return mHeight; }
- uint32_t getFormat() const { return mFormat; }
-
- // Dump stream information
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- enum {
- ERROR = -1,
- RELEASED = 0,
- ALLOCATED,
- CONNECTED,
- ACTIVE
- } mState;
-
- sp<ANativeWindow> mConsumerInterface;
- camera2_device_t *mHal2Device;
-
- uint32_t mId;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mFormat;
- size_t mSize;
- uint32_t mUsage;
- uint32_t mMaxProducerBuffers;
- uint32_t mMaxConsumerBuffers;
- uint32_t mTotalBuffers;
- int mFormatRequested;
-
- /** Debugging information */
- uint32_t mActiveBuffers;
- uint32_t mFrameCount;
- int64_t mLastTimestamp;
-
- const camera2_stream_ops *getStreamOps();
-
- static ANativeWindow* toANW(const camera2_stream_ops_t *w);
-
- static int dequeue_buffer(const camera2_stream_ops_t *w,
- buffer_handle_t** buffer);
-
- static int enqueue_buffer(const camera2_stream_ops_t* w,
- int64_t timestamp,
- buffer_handle_t* buffer);
-
- static int cancel_buffer(const camera2_stream_ops_t* w,
- buffer_handle_t* buffer);
-
- static int set_crop(const camera2_stream_ops_t* w,
- int left, int top, int right, int bottom);
- }; // class StreamAdapter
-
- typedef List<sp<StreamAdapter> > StreamList;
- StreamList mStreams;
-
- /**
- * Adapter from an ANativeWindow interface to camera2 device stream ops.
- * Also takes care of allocating/deallocating stream in device interface
- */
- class ReprocessStreamAdapter: public camera2_stream_in_ops, public virtual RefBase {
- public:
- ReprocessStreamAdapter(camera2_device_t *d);
-
- ~ReprocessStreamAdapter();
-
- /**
- * Create a HAL device reprocess stream based on an existing output stream.
- */
- status_t connectToDevice(const sp<StreamAdapter> &outputStream);
-
- status_t release();
-
- /**
- * Push buffer into stream for reprocessing. Takes ownership until it notifies
- * that the buffer has been released
- */
- status_t pushIntoStream(buffer_handle_t *handle,
- const wp<BufferReleasedListener> &releaseListener);
-
- /**
- * Get stream parameters.
- * Only valid after a successful connectToDevice call.
- */
- int getId() const { return mId; }
- uint32_t getWidth() const { return mWidth; }
- uint32_t getHeight() const { return mHeight; }
- uint32_t getFormat() const { return mFormat; }
-
- // Dump stream information
- status_t dump(int fd, const Vector<String16>& args);
-
- private:
- enum {
- ERROR = -1,
- RELEASED = 0,
- ACTIVE
- } mState;
-
- sp<ANativeWindow> mConsumerInterface;
- wp<StreamAdapter> mBaseStream;
-
- struct QueueEntry {
- buffer_handle_t *handle;
- wp<BufferReleasedListener> releaseListener;
- };
-
- List<QueueEntry> mQueue;
-
- List<QueueEntry> mInFlightQueue;
-
- camera2_device_t *mHal2Device;
-
- uint32_t mId;
- uint32_t mWidth;
- uint32_t mHeight;
- uint32_t mFormat;
-
- /** Debugging information */
- uint32_t mActiveBuffers;
- uint32_t mFrameCount;
- int64_t mLastTimestamp;
-
- const camera2_stream_in_ops *getStreamOps();
-
- static int acquire_buffer(const camera2_stream_in_ops_t *w,
- buffer_handle_t** buffer);
-
- static int release_buffer(const camera2_stream_in_ops_t* w,
- buffer_handle_t* buffer);
-
- }; // class ReprocessStreamAdapter
-
- typedef List<sp<ReprocessStreamAdapter> > ReprocessStreamList;
- ReprocessStreamList mReprocessStreams;
-
- // Receives HAL notifications and routes them to the NotificationListener
- static void notificationCallback(int32_t msg_type,
- int32_t ext1,
- int32_t ext2,
- int32_t ext3,
- void *user);
-
-}; // class Camera2Device
-
-}; // namespace android
-
-#endif
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 50d9d75..6c07aef 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -422,7 +422,31 @@
return maxBytesForPointCloud;
}
+ssize_t Camera3Device::getRawOpaqueBufferSize(uint32_t width, uint32_t height) const {
+ const int PER_CONFIGURATION_SIZE = 3;
+ const int WIDTH_OFFSET = 0;
+ const int HEIGHT_OFFSET = 1;
+ const int SIZE_OFFSET = 2;
+ camera_metadata_ro_entry rawOpaqueSizes =
+ mDeviceInfo.find(ANDROID_SENSOR_OPAQUE_RAW_SIZE);
+ int count = rawOpaqueSizes.count;
+ if (count == 0 || (count % PER_CONFIGURATION_SIZE)) {
+ ALOGE("%s: Camera %d: bad opaque RAW size static metadata length(%d)!",
+ __FUNCTION__, mId, count);
+ return BAD_VALUE;
+ }
+ for (size_t i = 0; i < count; i += PER_CONFIGURATION_SIZE) {
+ if (width == rawOpaqueSizes.data.i32[i + WIDTH_OFFSET] &&
+ height == rawOpaqueSizes.data.i32[i + HEIGHT_OFFSET]) {
+ return rawOpaqueSizes.data.i32[i + SIZE_OFFSET];
+ }
+ }
+
+ ALOGE("%s: Camera %d: cannot find size for %dx%d opaque RAW image!",
+ __FUNCTION__, mId, width, height);
+ return BAD_VALUE;
+}
status_t Camera3Device::dump(int fd, const Vector<String16> &args) {
ATRACE_CALL();
@@ -440,6 +464,15 @@
"Camera %d: %s: Unable to lock main lock, proceeding anyway",
mId, __FUNCTION__);
+ bool dumpTemplates = false;
+ String16 templatesOption("-t");
+ int n = args.size();
+ for (int i = 0; i < n; i++) {
+ if (args[i] == templatesOption) {
+ dumpTemplates = true;
+ }
+ }
+
String8 lines;
const char *status =
@@ -491,6 +524,33 @@
lastRequest.dump(fd, /*verbosity*/2, /*indentation*/6);
}
+ if (dumpTemplates) {
+ const char *templateNames[] = {
+ "TEMPLATE_PREVIEW",
+ "TEMPLATE_STILL_CAPTURE",
+ "TEMPLATE_VIDEO_RECORD",
+ "TEMPLATE_VIDEO_SNAPSHOT",
+ "TEMPLATE_ZERO_SHUTTER_LAG",
+ "TEMPLATE_MANUAL"
+ };
+
+ for (int i = 1; i < CAMERA3_TEMPLATE_COUNT; i++) {
+ const camera_metadata_t *templateRequest;
+ templateRequest =
+ mHal3Device->ops->construct_default_request_settings(
+ mHal3Device, i);
+ lines = String8::format(" HAL Request %s:\n", templateNames[i-1]);
+ if (templateRequest == NULL) {
+ lines.append(" Not supported\n");
+ write(fd, lines.string(), lines.size());
+ } else {
+ write(fd, lines.string(), lines.size());
+ dump_indented_camera_metadata(templateRequest,
+ fd, /*verbosity*/2, /*indentation*/8);
+ }
+ }
+ }
+
if (mHal3Device != NULL) {
lines = String8(" HAL device dump:\n");
write(fd, lines.string(), lines.size());
@@ -920,6 +980,14 @@
}
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, blobBufferSize, format, dataSpace, rotation);
+ } else if (format == HAL_PIXEL_FORMAT_RAW_OPAQUE) {
+ ssize_t rawOpaqueBufferSize = getRawOpaqueBufferSize(width, height);
+ if (rawOpaqueBufferSize <= 0) {
+ SET_ERR_L("Invalid RAW opaque buffer size %zd", rawOpaqueBufferSize);
+ return BAD_VALUE;
+ }
+ newStream = new Camera3OutputStream(mNextStreamId, consumer,
+ width, height, rawOpaqueBufferSize, format, dataSpace, rotation);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, format, dataSpace, rotation);
@@ -3266,7 +3334,7 @@
}
if (mNextRequests.size() < batchSize) {
- ALOGE("RequestThread: only get %d out of %d requests. Skipping requests.",
+ ALOGE("RequestThread: only get %zu out of %zu requests. Skipping requests.",
mNextRequests.size(), batchSize);
cleanUpFailedRequests(/*sendRequestError*/true);
}
@@ -3586,7 +3654,7 @@
status_t Camera3Device::RequestThread::addDummyTriggerIds(
const sp<CaptureRequest> &request) {
- // Trigger ID 0 has special meaning in the HAL2 spec, so avoid it here
+ // Trigger ID 0 had special meaning in the HAL2 spec, so avoid it here
static const int32_t dummyTriggerId = 1;
status_t res;
@@ -3680,8 +3748,6 @@
}
status_t Camera3Device::PreparerThread::clear() {
- status_t res;
-
Mutex::Autolock l(mLock);
for (const auto& stream : mPendingStreams) {
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2cd5af3..7e20b0d 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -150,6 +150,7 @@
virtual ssize_t getJpegBufferSize(uint32_t width, uint32_t height) const;
ssize_t getPointCloudBufferSize() const;
+ ssize_t getRawOpaqueBufferSize(uint32_t width, uint32_t height) const;
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
diff --git a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
index 23b1c45..7b298e6 100644
--- a/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
+++ b/services/camera/libcameraservice/device3/Camera3IOStreamBase.cpp
@@ -42,7 +42,8 @@
mCombinedFence = new Fence();
- if (maxSize > 0 && format != HAL_PIXEL_FORMAT_BLOB) {
+ if (maxSize > 0 &&
+ (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
format);
mState = STATE_ERROR;
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index 3f0a736..a5aa1fa 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -57,7 +57,7 @@
mTransform(0),
mTraceFirstBuffer(true) {
- if (format != HAL_PIXEL_FORMAT_BLOB) {
+ if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
format);
mState = STATE_ERROR;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 96299b3..141f6c3 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -66,8 +66,9 @@
camera3_stream::max_buffers = 0;
camera3_stream::priv = NULL;
- if (format == HAL_PIXEL_FORMAT_BLOB && maxSize == 0) {
- ALOGE("%s: BLOB format with size == 0", __FUNCTION__);
+ if ((format == HAL_PIXEL_FORMAT_BLOB || format == HAL_PIXEL_FORMAT_RAW_OPAQUE) &&
+ maxSize == 0) {
+ ALOGE("%s: BLOB or RAW_OPAQUE format with size == 0", __FUNCTION__);
mState = STATE_ERROR;
}
}
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
index 8cd6800..65816e0 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.cpp
@@ -229,7 +229,7 @@
// item.mGraphicBuffer was populated with the proper graphic-buffer
// at acquire even if it was previously acquired
- err = addReleaseFenceLocked(item.mBuf,
+ err = addReleaseFenceLocked(item.mSlot,
item.mGraphicBuffer, item.mFence);
if (err != OK) {
@@ -244,7 +244,7 @@
// item.mGraphicBuffer was populated with the proper graphic-buffer
// at acquire even if it was previously acquired
- err = releaseBufferLocked(item.mBuf, item.mGraphicBuffer,
+ err = releaseBufferLocked(item.mSlot, item.mGraphicBuffer,
EGL_NO_DISPLAY,
EGL_NO_SYNC_KHR);
if (err != OK) {
@@ -318,7 +318,7 @@
mLatestTimestamp = item.mTimestamp;
- item.mGraphicBuffer = mSlots[item.mBuf].mGraphicBuffer;
+ item.mGraphicBuffer = mSlots[item.mSlot].mGraphicBuffer;
} // end of mMutex lock
ConsumerBase::onFrameAvailable(item);
@@ -335,7 +335,7 @@
RingBufferItem& find = *it;
if (item.mGraphicBuffer == find.mGraphicBuffer) {
- status_t res = addReleaseFenceLocked(item.mBuf,
+ status_t res = addReleaseFenceLocked(item.mSlot,
item.mGraphicBuffer, item.mFence);
if (res != OK) {
diff --git a/services/camera/libcameraservice/gui/RingBufferConsumer.h b/services/camera/libcameraservice/gui/RingBufferConsumer.h
index 83e7298..243ea31 100644
--- a/services/camera/libcameraservice/gui/RingBufferConsumer.h
+++ b/services/camera/libcameraservice/gui/RingBufferConsumer.h
@@ -133,7 +133,7 @@
}
bool isEmpty() {
- return mBufferItem.mBuf == BufferQueue::INVALID_BUFFER_SLOT;
+ return mBufferItem.mSlot == BufferQueue::INVALID_BUFFER_SLOT;
}
BufferItem& getBufferItem() { return mBufferItem; }
diff --git a/services/mediaextractor/Android.mk b/services/mediaextractor/Android.mk
new file mode 100644
index 0000000..21a75cd
--- /dev/null
+++ b/services/mediaextractor/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+
+# service library
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := MediaExtractorService.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libstagefright libbinder libutils liblog
+LOCAL_MODULE:= libmediaextractorservice
+LOCAL_32_BIT_ONLY := true
+include $(BUILD_SHARED_LIBRARY)
+
+
+# service executable
+include $(CLEAR_VARS)
+LOCAL_REQUIRED_MODULES_arm := mediaextractor-seccomp.policy
+LOCAL_SRC_FILES := main_extractorservice.cpp minijail/minijail.cpp
+LOCAL_SHARED_LIBRARIES := libmedia libmediaextractorservice libbinder libutils liblog libicuuc libminijail
+LOCAL_STATIC_LIBRARIES := libicuandroid_utils
+LOCAL_MODULE:= mediaextractor
+LOCAL_32_BIT_ONLY := true
+LOCAL_INIT_RC := mediaextractor.rc
+include $(BUILD_EXECUTABLE)
+
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/services/mediaextractor/MODULE_LICENSE_APACHE2 b/services/mediaextractor/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/services/mediaextractor/MODULE_LICENSE_APACHE2
diff --git a/services/mediaextractor/MediaExtractorService.cpp b/services/mediaextractor/MediaExtractorService.cpp
new file mode 100644
index 0000000..cd20635
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorService.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2013 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 "MediaExtractorService"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaExtractor.h>
+#include "MediaExtractorService.h"
+
+namespace android {
+
+sp<IMediaExtractor> MediaExtractorService::makeExtractor(
+ const sp<IDataSource> &remoteSource, const char *mime) {
+ ALOGV("@@@ MediaExtractorService::makeExtractor for %s", mime);
+
+ sp<DataSource> localSource = DataSource::CreateFromIDataSource(remoteSource);
+
+ sp<MediaExtractor> ret = MediaExtractor::CreateFromService(localSource, mime);
+
+ ALOGV("extractor service created %p (%s)",
+ ret.get(),
+ ret == NULL ? "" : ret->name());
+
+ return ret;
+}
+
+
+status_t MediaExtractorService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags)
+{
+ return BnMediaExtractorService::onTransact(code, data, reply, flags);
+}
+
+} // namespace android
diff --git a/services/mediaextractor/MediaExtractorService.h b/services/mediaextractor/MediaExtractorService.h
new file mode 100644
index 0000000..9c75042
--- /dev/null
+++ b/services/mediaextractor/MediaExtractorService.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_EXTRACTOR_SERVICE_H
+#define ANDROID_MEDIA_EXTRACTOR_SERVICE_H
+
+#include <binder/BinderService.h>
+#include <media/IMediaExtractorService.h>
+#include <media/IMediaExtractor.h>
+
+namespace android {
+
+class MediaExtractorService : public BinderService<MediaExtractorService>, public BnMediaExtractorService
+{
+ friend class BinderService<MediaExtractorService>; // for MediaExtractorService()
+public:
+ MediaExtractorService() : BnMediaExtractorService() { }
+ virtual ~MediaExtractorService() { }
+ virtual void onFirstRef() { }
+
+ static const char* getServiceName() { return "media.extractor"; }
+
+ virtual sp<IMediaExtractor> makeExtractor(const sp<IDataSource> &source, const char *mime);
+
+ virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+ uint32_t flags);
+
+private:
+ Mutex mLock;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_EXTRACTOR_SERVICE_H
diff --git a/services/mediaextractor/NOTICE b/services/mediaextractor/NOTICE
new file mode 100644
index 0000000..34bdaf1
--- /dev/null
+++ b/services/mediaextractor/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/services/mediaextractor/main_extractorservice.cpp b/services/mediaextractor/main_extractorservice.cpp
new file mode 100644
index 0000000..a7f3fbe
--- /dev/null
+++ b/services/mediaextractor/main_extractorservice.cpp
@@ -0,0 +1,49 @@
+/*
+**
+** Copyright 2008, 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 "mediaextractor"
+//#define LOG_NDEBUG 0
+
+#include <fcntl.h>
+#include <sys/prctl.h>
+#include <sys/wait.h>
+#include <binder/IPCThreadState.h>
+#include <binder/ProcessState.h>
+#include <binder/IServiceManager.h>
+#include <utils/Log.h>
+
+// from LOCAL_C_INCLUDES
+#include "IcuUtils.h"
+#include "MediaExtractorService.h"
+#include "minijail/minijail.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv)
+{
+ signal(SIGPIPE, SIG_IGN);
+ MiniJail();
+
+ InitializeIcuOrDie();
+
+ strcpy(argv[0], "media.extractor");
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ MediaExtractorService::instantiate();
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/mediaextractor/mediaextractor.rc b/services/mediaextractor/mediaextractor.rc
new file mode 100644
index 0000000..f733a2b
--- /dev/null
+++ b/services/mediaextractor/mediaextractor.rc
@@ -0,0 +1,5 @@
+service mediaextractor /system/bin/mediaextractor
+ class main
+ user mediaex
+ group drmrpc mediadrm
+ ioprio rt 4
diff --git a/services/mediaextractor/minijail/Android.mk b/services/mediaextractor/minijail/Android.mk
new file mode 100644
index 0000000..17ff2c1
--- /dev/null
+++ b/services/mediaextractor/minijail/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH := $(call my-dir)
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH), arm arm64))
+include $(CLEAR_VARS)
+LOCAL_MODULE := mediaextractor-seccomp.policy
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT)/etc/seccomp_policy
+
+# mediaextractor runs in 32-bit combatibility mode. For 64 bit architectures,
+# use the 32 bit policy
+ifdef TARGET_2ND_ARCH
+ LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediaextractor-seccomp-$(TARGET_2ND_ARCH).policy
+else
+ LOCAL_SRC_FILES := $(LOCAL_PATH)/seccomp_policy/mediaextractor-seccomp-$(TARGET_ARCH).policy
+endif
+
+# allow device specific additions to the syscall whitelist
+ifneq (,$(wildcard $(BOARD_SECCOMP_POLICY)/mediaextractor-seccomp.policy))
+ LOCAL_SRC_FILES += $(BOARD_SECCOMP_POLICY)/mediaextractor-seccomp.policy
+endif
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE): $(LOCAL_SRC_FILES)
+ cat > $@ $^
+
+endif
diff --git a/services/mediaextractor/minijail/minijail.cpp b/services/mediaextractor/minijail/minijail.cpp
new file mode 100644
index 0000000..421a1e0
--- /dev/null
+++ b/services/mediaextractor/minijail/minijail.cpp
@@ -0,0 +1,50 @@
+/*
+**
+** Copyright 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.
+*/
+
+#include <cutils/log.h>
+#include <libminijail.h>
+
+#include "minijail.h"
+
+namespace android {
+
+/* Must match location in Android.mk */
+static const char kSeccompFilePath[] = "/system/etc/seccomp_policy/mediaextractor-seccomp.policy";
+
+int MiniJail()
+{
+ /* no seccomp policy for this architecture */
+ if (access(kSeccompFilePath, R_OK) == -1) {
+ ALOGW("No seccomp filter defined for this architecture.");
+ return 0;
+ }
+
+ struct minijail *jail = minijail_new();
+ if (jail == NULL) {
+ ALOGW("Failed to create minijail.");
+ return -1;
+ }
+
+ minijail_no_new_privs(jail);
+ minijail_log_seccomp_filter_failures(jail);
+ minijail_use_seccomp_filter(jail);
+ minijail_parse_seccomp_filters(jail, kSeccompFilePath);
+ minijail_enter(jail);
+ minijail_destroy(jail);
+ return 0;
+}
+}
diff --git a/services/mediaextractor/minijail/minijail.h b/services/mediaextractor/minijail/minijail.h
new file mode 100644
index 0000000..6ea4487
--- /dev/null
+++ b/services/mediaextractor/minijail/minijail.h
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 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.
+*/
+
+namespace android {
+int MiniJail();
+}
diff --git a/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
new file mode 100644
index 0000000..f23e38f
--- /dev/null
+++ b/services/mediaextractor/minijail/seccomp_policy/mediaextractor-seccomp-arm.policy
@@ -0,0 +1,39 @@
+# Organized by frequency of systemcall - in descending order for
+# best performance.
+ioctl: 1
+futex: 1
+openat: 1
+mmap2: 1
+fstatat64: 1
+writev: 1
+prctl: 1
+fcntl64: 1
+close: 1
+getuid32: 1
+restart_syscall: 1
+exit: 1
+exit_group: 1
+rt_sigreturn: 1
+clock_gettime: 1
+# Only allow local socket connections socket: arg0 == PF_LOCAL
+socket: arg0 == 1
+mprotect: 1
+faccessat: 1
+write: 1
+connect: 1
+fstat64: 1
+clone: 1
+dup: 1
+gettimeofday: 1
+getpriority: 1
+lseek: 1
+madvise: 1
+munmap: 1
+pread64: 1
+read: 1
+readlinkat: 1
+rt_sigprocmask: 1
+setpriority: 1
+sigaltstack: 1
+brk: 1
+sched_setscheduler: 1
diff --git a/services/radio/RadioService.cpp b/services/radio/RadioService.cpp
index cd0f5f3..57697f3 100644
--- a/services/radio/RadioService.cpp
+++ b/services/radio/RadioService.cpp
@@ -349,6 +349,7 @@
}
break;
case RADIO_EVENT_TA:
+ case RADIO_EVENT_EA:
case RADIO_EVENT_ANTENNA:
case RADIO_EVENT_CONTROL:
event->on = halEvent->on;