resolve merge conflicts of 3fce3ef to nyc-mr1-dev-plus-aosp
Change-Id: If319afe3976bedd64226e128164457f461eb7042
diff --git a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
index 1e8744b..96ecfa0 100644
--- a/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
+++ b/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl
@@ -121,4 +121,6 @@
void tearDown(int streamId);
void prepare2(int maxCount, int streamId);
+
+ void setDeferredConfiguration(int streamId, in OutputConfiguration outputConfiguration);
}
diff --git a/camera/camera2/OutputConfiguration.cpp b/camera/camera2/OutputConfiguration.cpp
index 3247d0d..38e1c01 100644
--- a/camera/camera2/OutputConfiguration.cpp
+++ b/camera/camera2/OutputConfiguration.cpp
@@ -42,9 +42,24 @@
return mSurfaceSetID;
}
+int OutputConfiguration::getSurfaceType() const {
+ return mSurfaceType;
+}
+
+int OutputConfiguration::getWidth() const {
+ return mWidth;
+}
+
+int OutputConfiguration::getHeight() const {
+ return mHeight;
+}
+
OutputConfiguration::OutputConfiguration() :
mRotation(INVALID_ROTATION),
- mSurfaceSetID(INVALID_SET_ID) {
+ mSurfaceSetID(INVALID_SET_ID),
+ mSurfaceType(SURFACE_TYPE_UNKNOWN),
+ mWidth(0),
+ mHeight(0) {
}
OutputConfiguration::OutputConfiguration(const Parcel& parcel) :
@@ -70,18 +85,48 @@
return err;
}
+ int surfaceType = SURFACE_TYPE_UNKNOWN;
+ if ((err = parcel->readInt32(&surfaceType)) != OK) {
+ ALOGE("%s: Failed to read surface type from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int width = 0;
+ if ((err = parcel->readInt32(&width)) != OK) {
+ ALOGE("%s: Failed to read surface width from parcel", __FUNCTION__);
+ return err;
+ }
+
+ int height = 0;
+ if ((err = parcel->readInt32(&height)) != OK) {
+ ALOGE("%s: Failed to read surface height from parcel", __FUNCTION__);
+ return err;
+ }
+
view::Surface surfaceShim;
if ((err = surfaceShim.readFromParcel(parcel)) != OK) {
- ALOGE("%s: Failed to read surface from parcel", __FUNCTION__);
- return err;
+ // Read surface failure for deferred surface configuration is expected.
+ if (surfaceType == SURFACE_TYPE_SURFACE_VIEW ||
+ surfaceType == SURFACE_TYPE_SURFACE_TEXTURE) {
+ ALOGV("%s: Get null surface from a deferred surface configuration (%dx%d)",
+ __FUNCTION__, width, height);
+ err = OK;
+ } else {
+ ALOGE("%s: Failed to read surface from parcel", __FUNCTION__);
+ return err;
+ }
}
mGbp = surfaceShim.graphicBufferProducer;
mRotation = rotation;
mSurfaceSetID = setID;
+ mSurfaceType = surfaceType;
+ mWidth = width;
+ mHeight = height;
- ALOGV("%s: OutputConfiguration: bp = %p, name = %s, rotation = %d, setId = %d", __FUNCTION__,
- mGbp.get(), String8(surfaceShim.name).string(), mRotation, mSurfaceSetID);
+ ALOGV("%s: OutputConfiguration: bp = %p, name = %s, rotation = %d, setId = %d,"
+ "surfaceType = %d", __FUNCTION__, mGbp.get(), String8(surfaceShim.name).string(),
+ mRotation, mSurfaceSetID, mSurfaceType);
return err;
}
@@ -104,6 +149,15 @@
err = parcel->writeInt32(mSurfaceSetID);
if (err != OK) return err;
+ err = parcel->writeInt32(mSurfaceType);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mWidth);
+ if (err != OK) return err;
+
+ err = parcel->writeInt32(mHeight);
+ if (err != OK) return err;
+
view::Surface surfaceShim;
surfaceShim.name = String16("unknown_name"); // name of surface
surfaceShim.graphicBufferProducer = mGbp;
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index 16d9da8..09f9789 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -1,6 +1,6 @@
service cameraserver /system/bin/cameraserver
class main
user cameraserver
- group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
+ group audio camera input drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct
ioprio rt 4
writepid /dev/cpuset/foreground/tasks
diff --git a/include/camera/camera2/OutputConfiguration.h b/include/camera/camera2/OutputConfiguration.h
index 72a3753..cf8f3c6 100644
--- a/include/camera/camera2/OutputConfiguration.h
+++ b/include/camera/camera2/OutputConfiguration.h
@@ -33,10 +33,17 @@
static const int INVALID_ROTATION;
static const int INVALID_SET_ID;
+ enum SurfaceType{
+ SURFACE_TYPE_UNKNOWN = -1,
+ SURFACE_TYPE_SURFACE_VIEW = 0,
+ SURFACE_TYPE_SURFACE_TEXTURE = 1
+ };
sp<IGraphicBufferProducer> getGraphicBufferProducer() const;
int getRotation() const;
int getSurfaceSetID() const;
-
+ int getSurfaceType() const;
+ int getWidth() const;
+ int getHeight() const;
/**
* Keep impl up-to-date with OutputConfiguration.java in frameworks/base
*/
@@ -60,7 +67,10 @@
bool operator == (const OutputConfiguration& other) const {
return (mGbp == other.mGbp &&
mRotation == other.mRotation &&
- mSurfaceSetID == other.mSurfaceSetID);
+ mSurfaceSetID == other.mSurfaceSetID &&
+ mSurfaceType == other.mSurfaceType &&
+ mWidth == other.mWidth &&
+ mHeight == other.mHeight);
}
bool operator != (const OutputConfiguration& other) const {
return !(*this == other);
@@ -71,6 +81,16 @@
if (mSurfaceSetID != other.mSurfaceSetID) {
return mSurfaceSetID < other.mSurfaceSetID;
}
+ if (mSurfaceType != other.mSurfaceType) {
+ return mSurfaceType < other.mSurfaceType;
+ }
+ if (mWidth != other.mWidth) {
+ return mWidth < other.mWidth;
+ }
+ if (mHeight != other.mHeight) {
+ return mHeight < other.mHeight;
+ }
+
return mRotation < other.mRotation;
}
bool operator > (const OutputConfiguration& other) const {
@@ -81,6 +101,9 @@
sp<IGraphicBufferProducer> mGbp;
int mRotation;
int mSurfaceSetID;
+ int mSurfaceType;
+ int mWidth;
+ int mHeight;
// helper function
static String16 readMaybeEmptyString16(const Parcel* parcel);
};
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index 2fa1a4e..63076e9 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -491,6 +491,9 @@
*/
uint32_t getInputFramesLost() const;
+ /* Get the flags */
+ audio_input_flags_t getFlags() const { AutoMutex _l(mLock); return mFlags; }
+
private:
/* copying audio record objects is not allowed */
AudioRecord(const AudioRecord& other);
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 984bc02..096f7ef 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -44,16 +44,6 @@
public:
DECLARE_META_INTERFACE(AudioFlinger);
- // or-able bits shared by createTrack and openRecord, but not all combinations make sense
- enum {
- TRACK_DEFAULT = 0, // client requests a default AudioTrack
- // FIXME: obsolete
- // TRACK_TIMED= 1, // client requests a TimedAudioTrack
- TRACK_FAST = 2, // client requests a fast AudioTrack or AudioRecord
- TRACK_OFFLOAD = 4, // client requests offload to hw codec
- TRACK_DIRECT = 8, // client requests a direct output
- };
- typedef uint32_t track_flags_t;
// invariant on exit for all APIs that return an sp<>:
// (return value != 0) == (*status == NO_ERROR)
@@ -67,7 +57,7 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *pFrameCount,
- track_flags_t *flags,
+ audio_output_flags_t *flags,
const sp<IMemory>& sharedBuffer,
// On successful return, AudioFlinger takes over the handle
// reference and will release it when the track is destroyed.
@@ -89,7 +79,7 @@
audio_channel_mask_t channelMask,
const String16& callingPackage,
size_t *pFrameCount,
- track_flags_t *flags,
+ audio_input_flags_t *flags,
pid_t pid,
pid_t tid, // -1 means unused, otherwise must be valid non-0
int clientUid,
diff --git a/include/media/IMediaSource.h b/include/media/IMediaSource.h
index 709f425..524e7aa 100644
--- a/include/media/IMediaSource.h
+++ b/include/media/IMediaSource.h
@@ -114,6 +114,9 @@
virtual status_t readMultiple(
Vector<MediaBuffer *> *buffers, uint32_t maxNumBuffers = 1) = 0;
+ // Returns true if |readMultiple| is supported, otherwise false.
+ virtual bool supportReadMultiple() = 0;
+
// Causes this source to suspend pulling data from its upstream source
// until a subsequent read-with-seek. Currently only supported by
// OMXCodec.
@@ -148,6 +151,10 @@
Vector<MediaBuffer *> * /* buffers */, uint32_t /* maxNumBuffers = 1 */) {
return ERROR_UNSUPPORTED;
}
+
+ virtual bool supportReadMultiple() {
+ return false;
+ }
protected:
virtual ~BnMediaSource();
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index d9bb856..9a87023 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -593,11 +593,10 @@
size_t notificationFrames = mNotificationFramesReq;
size_t frameCount = mReqFrameCount;
- IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
+ audio_input_flags_t flags = mFlags;
pid_t tid = -1;
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
- trackFlags |= IAudioFlinger::TRACK_FAST;
if (mAudioRecordThread != 0) {
tid = mAudioRecordThread->getTid();
}
@@ -615,7 +614,7 @@
mChannelMask,
opPackageName,
&temp,
- &trackFlags,
+ &flags,
mClientPid,
tid,
mClientUid,
@@ -638,7 +637,7 @@
mAwaitBoost = false;
if (mFlags & AUDIO_INPUT_FLAG_FAST) {
- if (trackFlags & IAudioFlinger::TRACK_FAST) {
+ if (flags & AUDIO_INPUT_FLAG_FAST) {
ALOGI("AUDIO_INPUT_FLAG_FAST successful; frameCount %zu", frameCount);
mAwaitBoost = true;
} else {
@@ -648,6 +647,7 @@
continue; // retry
}
}
+ mFlags = flags;
if (iMem == 0) {
ALOGE("Could not get control block");
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index e8c3466..ed7b856 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -1372,24 +1372,15 @@
}
}
- IAudioFlinger::track_flags_t trackFlags = IAudioFlinger::TRACK_DEFAULT;
+ audio_output_flags_t flags = mFlags;
pid_t tid = -1;
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
- trackFlags |= IAudioFlinger::TRACK_FAST;
if (mAudioTrackThread != 0 && !mThreadCanCallJava) {
tid = mAudioTrackThread->getTid();
}
}
- if (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
- trackFlags |= IAudioFlinger::TRACK_OFFLOAD;
- }
-
- if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
- trackFlags |= IAudioFlinger::TRACK_DIRECT;
- }
-
size_t temp = frameCount; // temp may be replaced by a revised value of frameCount,
// but we will still need the original value also
audio_session_t originalSessionId = mSessionId;
@@ -1398,7 +1389,7 @@
mFormat,
mChannelMask,
&temp,
- &trackFlags,
+ &flags,
mSharedBuffer,
output,
mClientPid,
@@ -1451,23 +1442,23 @@
mAwaitBoost = false;
if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
- if (trackFlags & IAudioFlinger::TRACK_FAST) {
+ if (flags & AUDIO_OUTPUT_FLAG_FAST) {
ALOGV("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %zu", frameCount);
if (!mThreadCanCallJava) {
mAwaitBoost = true;
}
} else {
ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %zu", frameCount);
- mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_FAST);
}
}
+ mFlags = flags;
// Make sure that application is notified with sufficient margin before underrun.
// The client can divide the AudioTrack buffer into sub-buffers,
// and expresses its desire to server as the notification frame count.
if (mSharedBuffer == 0 && audio_is_linear_pcm(mFormat)) {
size_t maxNotificationFrames;
- if (trackFlags & IAudioFlinger::TRACK_FAST) {
+ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) {
// notify every HAL buffer, regardless of the size of the track buffer
maxNotificationFrames = afFrameCountHAL;
} else {
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index 4fc3c9f..65fdedb 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -101,7 +101,7 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *pFrameCount,
- track_flags_t *flags,
+ audio_output_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t pid,
@@ -119,7 +119,7 @@
data.writeInt32(channelMask);
size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
data.writeInt64(frameCount);
- track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
+ audio_output_flags_t lFlags = flags != NULL ? *flags : AUDIO_OUTPUT_FLAG_NONE;
data.writeInt32(lFlags);
// haveSharedBuffer
if (sharedBuffer != 0) {
@@ -145,7 +145,7 @@
if (pFrameCount != NULL) {
*pFrameCount = frameCount;
}
- lFlags = reply.readInt32();
+ lFlags = (audio_output_flags_t)reply.readInt32();
if (flags != NULL) {
*flags = lFlags;
}
@@ -180,7 +180,7 @@
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *pFrameCount,
- track_flags_t *flags,
+ audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
@@ -200,7 +200,7 @@
data.writeString16(opPackageName);
size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0;
data.writeInt64(frameCount);
- track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
+ audio_input_flags_t lFlags = flags != NULL ? *flags : AUDIO_INPUT_FLAG_NONE;
data.writeInt32(lFlags);
data.writeInt32((int32_t) pid);
data.writeInt32((int32_t) tid);
@@ -221,7 +221,7 @@
if (pFrameCount != NULL) {
*pFrameCount = frameCount;
}
- lFlags = reply.readInt32();
+ lFlags = (audio_input_flags_t)reply.readInt32();
if (flags != NULL) {
*flags = lFlags;
}
@@ -947,7 +947,7 @@
audio_format_t format = (audio_format_t) data.readInt32();
audio_channel_mask_t channelMask = data.readInt32();
size_t frameCount = data.readInt64();
- track_flags_t flags = (track_flags_t) data.readInt32();
+ audio_output_flags_t flags = (audio_output_flags_t) data.readInt32();
bool haveSharedBuffer = data.readInt32() != 0;
sp<IMemory> buffer;
if (haveSharedBuffer) {
@@ -986,7 +986,7 @@
audio_channel_mask_t channelMask = data.readInt32();
const String16& opPackageName = data.readString16();
size_t frameCount = data.readInt64();
- track_flags_t flags = (track_flags_t) data.readInt32();
+ audio_input_flags_t flags = (audio_input_flags_t) data.readInt32();
pid_t pid = (pid_t) data.readInt32();
pid_t tid = (pid_t) data.readInt32();
int clientUid = data.readInt32();
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index 7e40e4f..d2b4291 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -221,6 +221,10 @@
return ret;
}
+ bool supportReadMultiple() {
+ return true;
+ }
+
virtual status_t pause() {
ALOGV("pause");
Parcel data, reply;
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 8725dfe..fbe749c 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -395,7 +395,9 @@
return BAD_VALUE;
}
Mutex::Autolock _l(mLock);
- if (mPlayer == 0) return INVALID_OPERATION;
+ if (mPlayer == 0 || (mCurrentState & MEDIA_PLAYER_STOPPED)) {
+ return INVALID_OPERATION;
+ }
if (rate.mSpeed != 0.f && !(mCurrentState & MEDIA_PLAYER_STARTED)
&& (mCurrentState & (MEDIA_PLAYER_PREPARED | MEDIA_PLAYER_PAUSED
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index 56042d4..3d836c8 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -1420,7 +1420,9 @@
options.setNonBlocking();
}
- bool couldReadMultiple = (!mIsWidevine && trackType == MEDIA_TRACK_TYPE_AUDIO);
+ bool couldReadMultiple =
+ (!mIsWidevine && trackType == MEDIA_TRACK_TYPE_AUDIO
+ && track->mSource->supportReadMultiple());
for (size_t numBuffers = 0; numBuffers < maxBuffers; ) {
Vector<MediaBuffer *> mediaBuffers;
status_t err = NO_ERROR;
diff --git a/media/libstagefright/MediaCodecSource.cpp b/media/libstagefright/MediaCodecSource.cpp
index d7cf1e9..ff59fb1 100644
--- a/media/libstagefright/MediaCodecSource.cpp
+++ b/media/libstagefright/MediaCodecSource.cpp
@@ -648,6 +648,15 @@
CHECK(mbuf->meta_data()->findInt64(kKeyTime, &timeUs));
timeUs += mInputBufferTimeOffsetUs;
+ // Due to the extra delay adjustment at the beginning of start/resume,
+ // the adjusted timeUs may be negative if MediaCodecSource goes into pause
+ // state before feeding any buffers to the encoder. Drop the buffer in this
+ // case.
+ if (timeUs < 0) {
+ mbuf->release();
+ return OK;
+ }
+
// push decoding time for video, or drift time for audio
if (mIsVideo) {
mDecodingTimeQueue.push_back(timeUs);
@@ -832,9 +841,16 @@
// 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);
+
+ // Due to the extra delay adjustment at the beginning of
+ // start/resume, the adjusted timeUs may be negative if
+ // MediaCodecSource goes into pause state before feeding
+ // any buffers to the encoder. Drop the buffer in this case.
+ if (timeUs < 0) {
+ mEncoder->releaseOutputBuffer(index);
+ break;
+ }
+
// TODO:
// Decoding time for surface source is unavailable,
// use presentation time for now. May need to move
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index c429a7f..a757aac 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -576,7 +576,7 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *frameCount,
- IAudioFlinger::track_flags_t *flags,
+ audio_output_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t pid,
@@ -1467,7 +1467,7 @@
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *frameCount,
- IAudioFlinger::track_flags_t *flags,
+ audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
@@ -2199,7 +2199,7 @@
}
#endif
- AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream);
+ AudioStreamIn *inputStream = new AudioStreamIn(inHwDev, inStream, flags);
// Start record thread
// RecordThread requires both input and output device indication to forward to audio
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 59ad688..4a5a643 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -104,7 +104,7 @@
audio_format_t format,
audio_channel_mask_t channelMask,
size_t *pFrameCount,
- IAudioFlinger::track_flags_t *flags,
+ audio_output_flags_t *flags,
const sp<IMemory>& sharedBuffer,
audio_io_handle_t output,
pid_t pid,
@@ -120,7 +120,7 @@
audio_channel_mask_t channelMask,
const String16& opPackageName,
size_t *pFrameCount,
- IAudioFlinger::track_flags_t *flags,
+ audio_input_flags_t *flags,
pid_t pid,
pid_t tid,
int clientUid,
@@ -609,11 +609,12 @@
struct AudioStreamIn {
AudioHwDevice* const audioHwDev;
audio_stream_in_t* const stream;
+ audio_input_flags_t flags;
audio_hw_device_t* hwDev() const { return audioHwDev->hwDevice(); }
- AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in) :
- audioHwDev(dev), stream(in) {}
+ AudioStreamIn(AudioHwDevice *dev, audio_stream_in_t *in, audio_input_flags_t flags) :
+ audioHwDev(dev), stream(in), flags(flags) {}
};
// for mAudioSessionRefs only
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index f8671b5..bee17fd 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -168,12 +168,46 @@
ALOGV("createAudioPatch() removing patch handle %d", *handle);
halHandle = mPatches[index]->mHalHandle;
Patch *removedPatch = mPatches[index];
+ // free resources owned by the removed patch if applicable
+ // 1) if a software patch is present, release the playback and capture threads and
+ // tracks created. This will also release the corresponding audio HAL patches
if ((removedPatch->mRecordPatchHandle
!= AUDIO_PATCH_HANDLE_NONE) ||
(removedPatch->mPlaybackPatchHandle !=
AUDIO_PATCH_HANDLE_NONE)) {
clearPatchConnections(removedPatch);
}
+ // 2) if the new patch and old patch source or sink are devices from different
+ // hw modules, clear the audio HAL patches now because they will not be updated
+ // by call to create_audio_patch() below which will happen on a different HW module
+ if (halHandle != AUDIO_PATCH_HANDLE_NONE) {
+ audio_module_handle_t hwModule = AUDIO_MODULE_HANDLE_NONE;
+ if ((removedPatch->mAudioPatch.sources[0].type == AUDIO_PORT_TYPE_DEVICE) &&
+ ((patch->sources[0].type != AUDIO_PORT_TYPE_DEVICE) ||
+ (removedPatch->mAudioPatch.sources[0].ext.device.hw_module !=
+ patch->sources[0].ext.device.hw_module))) {
+ hwModule = removedPatch->mAudioPatch.sources[0].ext.device.hw_module;
+ } else if ((patch->num_sinks == 0) ||
+ ((removedPatch->mAudioPatch.sinks[0].type == AUDIO_PORT_TYPE_DEVICE) &&
+ ((patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) ||
+ (removedPatch->mAudioPatch.sinks[0].ext.device.hw_module !=
+ patch->sinks[0].ext.device.hw_module)))) {
+ // Note on (patch->num_sinks == 0): this situation should not happen as
+ // these special patches are only created by the policy manager but just
+ // in case, systematically clear the HAL patch.
+ // Note that removedPatch->mAudioPatch.num_sinks cannot be 0 here because
+ // halHandle would be AUDIO_PATCH_HANDLE_NONE in this case.
+ hwModule = removedPatch->mAudioPatch.sinks[0].ext.device.hw_module;
+ }
+ if (hwModule != AUDIO_MODULE_HANDLE_NONE) {
+ ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(hwModule);
+ if (index >= 0) {
+ audio_hw_device_t *hwDevice =
+ audioflinger->mAudioHwDevs.valueAt(index)->hwDevice();
+ hwDevice->release_audio_patch(hwDevice, halHandle);
+ }
+ }
+ }
mPatches.removeAt(index);
delete removedPatch;
break;
@@ -437,7 +471,7 @@
format,
frameCount,
NULL,
- IAudioFlinger::TRACK_DEFAULT);
+ AUDIO_INPUT_FLAG_NONE);
if (patch->mPatchRecord == 0) {
return NO_MEMORY;
}
@@ -457,7 +491,7 @@
format,
frameCount,
patch->mPatchRecord->buffer(),
- IAudioFlinger::TRACK_DEFAULT);
+ AUDIO_OUTPUT_FLAG_NONE);
if (patch->mPatchTrack == 0) {
return NO_MEMORY;
}
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index e31179c..16ec278 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -62,12 +62,24 @@
struct audio_patch mAudioPatch;
audio_patch_handle_t mHandle;
+ // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
audio_patch_handle_t mHalHandle;
+ // below members are used by a software audio patch connecting a source device from a
+ // given audio HW module to a sink device on an other audio HW module.
+ // playback thread created by createAudioPatch() and released by clearPatchConnections() if
+ // no existing playback thread can be used by the software patch
sp<PlaybackThread> mPlaybackThread;
+ // audio track created by createPatchConnections() and released by clearPatchConnections()
sp<PlaybackThread::PatchTrack> mPatchTrack;
+ // record thread created by createAudioPatch() and released by clearPatchConnections()
sp<RecordThread> mRecordThread;
+ // audio record created by createPatchConnections() and released by clearPatchConnections()
sp<RecordThread::PatchRecord> mPatchRecord;
+ // handle for audio patch connecting source device to record thread input.
+ // created by createPatchConnections() and released by clearPatchConnections()
audio_patch_handle_t mRecordPatchHandle;
+ // handle for audio patch connecting playback thread output to sink device
+ // created by createPatchConnections() and released by clearPatchConnections()
audio_patch_handle_t mPlaybackPatchHandle;
};
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 270e27f..5601bde 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -33,7 +33,7 @@
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
int uid,
- IAudioFlinger::track_flags_t flags,
+ audio_output_flags_t flags,
track_type type);
virtual ~Track();
virtual status_t initCheck() const;
@@ -55,8 +55,9 @@
audio_stream_type_t streamType() const {
return mStreamType;
}
- bool isOffloaded() const { return (mFlags & IAudioFlinger::TRACK_OFFLOAD) != 0; }
- bool isDirect() const { return (mFlags & IAudioFlinger::TRACK_DIRECT) != 0; }
+ bool isOffloaded() const
+ { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; }
+ bool isDirect() const { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; }
status_t setParameters(const String8& keyValuePairs);
status_t attachAuxEffect(int EffectId);
void setAuxBuffer(int EffectId, int32_t *buffer);
@@ -72,6 +73,8 @@
virtual status_t setSyncEvent(const sp<SyncEvent>& event);
+ virtual bool isFastTrack() const { return (mFlags & AUDIO_OUTPUT_FLAG_FAST) != 0; }
+
protected:
// for numerous
friend class PlaybackThread;
@@ -166,7 +169,7 @@
AudioTrackServerProxy* mAudioTrackServerProxy;
bool mResumeToStopping; // track was paused in stopping state.
bool mFlushHwPending; // track requests for thread flush
-
+ audio_output_flags_t mFlags;
}; // end of Track
@@ -226,7 +229,7 @@
audio_format_t format,
size_t frameCount,
void *buffer,
- IAudioFlinger::track_flags_t flags);
+ audio_output_flags_t flags);
virtual ~PatchTrack();
virtual status_t start(AudioSystem::sync_event_t event =
diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h
index 13396a6..123e033 100644
--- a/services/audioflinger/RecordTracks.h
+++ b/services/audioflinger/RecordTracks.h
@@ -31,7 +31,7 @@
void *buffer,
audio_session_t sessionId,
int uid,
- IAudioFlinger::track_flags_t flags,
+ audio_input_flags_t flags,
track_type type);
virtual ~RecordTrack();
virtual status_t initCheck() const;
@@ -58,6 +58,9 @@
int64_t sourceFramesRead,
uint32_t halSampleRate,
const ExtendedTimestamp ×tamp);
+
+ virtual bool isFastTrack() const { return (mFlags & AUDIO_INPUT_FLAG_FAST) != 0; }
+
private:
friend class AudioFlinger; // for mState
@@ -86,6 +89,7 @@
// used by the record thread to convert frames to proper destination format
RecordBufferConverter *mRecordBufferConverter;
+ audio_input_flags_t mFlags;
};
// playback track, used by PatchPanel
@@ -98,7 +102,7 @@
audio_format_t format,
size_t frameCount,
void *buffer,
- IAudioFlinger::track_flags_t flags);
+ audio_input_flags_t flags);
virtual ~PatchRecord();
// AudioBufferProvider interface
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index cab5517..20b259a 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1753,7 +1753,7 @@
size_t *pFrameCount,
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
- IAudioFlinger::track_flags_t *flags,
+ audio_output_flags_t *flags,
pid_t tid,
int uid,
status_t *status)
@@ -1761,9 +1761,22 @@
size_t frameCount = *pFrameCount;
sp<Track> track;
status_t lStatus;
+ audio_output_flags_t outputFlags = mOutput->flags;
+
+ // special case for FAST flag considered OK if fast mixer is present
+ if (hasFastMixer()) {
+ outputFlags = (audio_output_flags_t)(outputFlags | AUDIO_OUTPUT_FLAG_FAST);
+ }
+
+ // Check if requested flags are compatible with output stream flags
+ if ((*flags & outputFlags) != *flags) {
+ ALOGW("createTrack_l(): mismatch between requested flags (%08x) and output flags (%08x)",
+ *flags, outputFlags);
+ *flags = (audio_output_flags_t)(*flags & outputFlags);
+ }
// client expresses a preference for FAST, but we get the final say
- if (*flags & IAudioFlinger::TRACK_FAST) {
+ if (*flags & AUDIO_OUTPUT_FLAG_FAST) {
if (
// PCM data
audio_is_linear_pcm(format) &&
@@ -1801,7 +1814,7 @@
sharedBuffer.get(), frameCount, mFrameCount, format, mFormat,
audio_is_linear_pcm(format),
channelMask, sampleRate, mSampleRate, hasFastMixer(), tid, mFastTrackAvailMask);
- *flags &= ~IAudioFlinger::TRACK_FAST;
+ *flags = (audio_output_flags_t)(*flags &~AUDIO_OUTPUT_FLAG_FAST);
}
}
// For normal PCM streaming tracks, update minimum frame count.
@@ -1809,7 +1822,7 @@
// to be at least 2 x the normal mixer frame count and cover audio hardware latency.
// This is probably too conservative, but legacy application code may depend on it.
// If you change this calculation, also review the start threshold which is related.
- if (!(*flags & IAudioFlinger::TRACK_FAST)
+ if (!(*flags & AUDIO_OUTPUT_FLAG_FAST)
&& audio_has_proportional_frames(format) && sharedBuffer == 0) {
// this must match AudioTrack.cpp calculateMinFrameCount().
// TODO: Move to a common library
@@ -1917,7 +1930,7 @@
chain->incTrackCnt();
}
- if ((*flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
+ if ((*flags & AUDIO_OUTPUT_FLAG_FAST) && (tid != -1)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
// we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
// so ask activity manager to do this on our behalf
@@ -2285,6 +2298,7 @@
kUseFastMixer == FastMixer_Dynamic)) {
size_t minNormalFrameCount = (kMinNormalSinkBufferSizeMs * mSampleRate) / 1000;
size_t maxNormalFrameCount = (kMaxNormalSinkBufferSizeMs * mSampleRate) / 1000;
+
// round up minimum and round down maximum to nearest 16 frames to satisfy AudioMixer
minNormalFrameCount = (minNormalFrameCount + 15) & ~15;
maxNormalFrameCount = maxNormalFrameCount & ~15;
@@ -2301,18 +2315,7 @@
multiplier = (double) maxNormalFrameCount / (double) mFrameCount;
}
} else {
- // prefer an even multiplier, for compatibility with doubling of fast tracks due to HAL
- // SRC (it would be unusual for the normal sink buffer size to not be a multiple of fast
- // track, but we sometimes have to do this to satisfy the maximum frame count
- // constraint)
- // FIXME this rounding up should not be done if no HAL SRC
- uint32_t truncMult = (uint32_t) multiplier;
- if ((truncMult & 1)) {
- if ((truncMult + 1) * mFrameCount <= maxNormalFrameCount) {
- ++truncMult;
- }
- }
- multiplier = (double) truncMult;
+ multiplier = floor(multiplier);
}
}
mNormalFrameCount = multiplier * mFrameCount;
@@ -3175,6 +3178,11 @@
// (1) mixer threads without a fast mixer (which has its own warm-up)
// (2) minimum buffer sized tracks (even if the track is full,
// the app won't fill fast enough to handle the sudden draw).
+ //
+ // Total time spent in last processing cycle equals time spent in
+ // 1. threadLoop_write, as well as time spent in
+ // 2. threadLoop_mix (significant for heavy mixing, especially
+ // on low tier processors)
// it's OK if deltaMs is an overestimate.
const int32_t deltaMs =
@@ -6282,16 +6290,30 @@
audio_session_t sessionId,
size_t *notificationFrames,
int uid,
- IAudioFlinger::track_flags_t *flags,
+ audio_input_flags_t *flags,
pid_t tid,
status_t *status)
{
size_t frameCount = *pFrameCount;
sp<RecordTrack> track;
status_t lStatus;
+ audio_input_flags_t inputFlags = mInput->flags;
+
+ // special case for FAST flag considered OK if fast capture is present
+ if (hasFastCapture()) {
+ inputFlags = (audio_input_flags_t)(inputFlags | AUDIO_INPUT_FLAG_FAST);
+ }
+
+ // Check if requested flags are compatible with output stream flags
+ if ((*flags & inputFlags) != *flags) {
+ ALOGW("createRecordTrack_l(): mismatch between requested flags (%08x) and"
+ " input flags (%08x)",
+ *flags, inputFlags);
+ *flags = (audio_input_flags_t)(*flags & inputFlags);
+ }
// client expresses a preference for FAST, but we get the final say
- if (*flags & IAudioFlinger::TRACK_FAST) {
+ if (*flags & AUDIO_INPUT_FLAG_FAST) {
if (
// we formerly checked for a callback handler (non-0 tid),
// but that is no longer required for TRANSFER_OBTAIN mode
@@ -6320,12 +6342,12 @@
frameCount, mFrameCount, mPipeFramesP2,
format, audio_is_linear_pcm(format), channelMask, sampleRate, mSampleRate,
hasFastCapture(), tid, mFastTrackAvail);
- *flags &= ~IAudioFlinger::TRACK_FAST;
+ *flags = (audio_input_flags_t)(*flags & ~AUDIO_INPUT_FLAG_FAST);
}
}
// compute track buffer size in frames, and suggest the notification frame count
- if (*flags & IAudioFlinger::TRACK_FAST) {
+ if (*flags & AUDIO_INPUT_FLAG_FAST) {
// fast track: frame count is exactly the pipe depth
frameCount = mPipeFramesP2;
// ignore requested notificationFrames, and always notify exactly once every HAL buffer
@@ -6381,7 +6403,7 @@
setEffectSuspended_l(FX_IID_AEC, suspend, sessionId);
setEffectSuspended_l(FX_IID_NS, suspend, sessionId);
- if ((*flags & IAudioFlinger::TRACK_FAST) && (tid != -1)) {
+ if ((*flags & AUDIO_INPUT_FLAG_FAST) && (tid != -1)) {
pid_t callingPid = IPCThreadState::self()->getCallingPid();
// we don't have CAP_SYS_NICE, nor do we want to have it as it's too powerful,
// so ask activity manager to do this on our behalf
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 787b5c4..0b4fbb9 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -566,7 +566,7 @@
size_t *pFrameCount,
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
- IAudioFlinger::track_flags_t *flags,
+ audio_output_flags_t *flags,
pid_t tid,
int uid,
status_t *status /*non-NULL*/);
@@ -1258,7 +1258,7 @@
audio_session_t sessionId,
size_t *notificationFrames,
int uid,
- IAudioFlinger::track_flags_t *flags,
+ audio_input_flags_t *flags,
pid_t tid,
status_t *status /*non-NULL*/);
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 67a5e58..6b97246 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -63,7 +63,6 @@
void *buffer,
audio_session_t sessionId,
int uid,
- IAudioFlinger::track_flags_t flags,
bool isOut,
alloc_type alloc = ALLOC_CBLK,
track_type type = TYPE_DEFAULT);
@@ -81,7 +80,7 @@
sp<IMemory> getBuffers() const { return mBufferMemory; }
void* buffer() const { return mBuffer; }
- bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; }
+ virtual bool isFastTrack() const = 0;
bool isOutputTrack() const { return (mType == TYPE_OUTPUT); }
bool isPatchTrack() const { return (mType == TYPE_PATCH); }
bool isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }
@@ -156,7 +155,6 @@
const audio_session_t mSessionId;
int mUid;
Vector < sp<SyncEvent> >mSyncEvents;
- const IAudioFlinger::track_flags_t mFlags;
const bool mIsOut;
ServerProxy* mServerProxy;
const int mId;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 364e339..b387af3 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -73,7 +73,6 @@
void *buffer,
audio_session_t sessionId,
int clientUid,
- IAudioFlinger::track_flags_t flags,
bool isOut,
alloc_type alloc,
track_type type)
@@ -93,7 +92,6 @@
mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)),
mFrameCount(frameCount),
mSessionId(sessionId),
- mFlags(flags),
mIsOut(isOut),
mServerProxy(NULL),
mId(android_atomic_inc(&nextTrackId)),
@@ -345,11 +343,11 @@
const sp<IMemory>& sharedBuffer,
audio_session_t sessionId,
int uid,
- IAudioFlinger::track_flags_t flags,
+ audio_output_flags_t flags,
track_type type)
: TrackBase(thread, client, sampleRate, format, channelMask, frameCount,
(sharedBuffer != 0) ? sharedBuffer->pointer() : buffer,
- sessionId, uid, flags, true /*isOut*/,
+ sessionId, uid, true /*isOut*/,
(type == TYPE_PATCH) ? ( buffer == NULL ? ALLOC_LOCAL : ALLOC_NONE) : ALLOC_CBLK,
type),
mFillingUpStatus(FS_INVALID),
@@ -368,7 +366,8 @@
mIsInvalid(false),
mAudioTrackServerProxy(NULL),
mResumeToStopping(false),
- mFlushHwPending(false)
+ mFlushHwPending(false),
+ mFlags(flags)
{
// client == 0 implies sharedBuffer == 0
ALOG_ASSERT(!(client == 0 && sharedBuffer != 0));
@@ -395,7 +394,7 @@
return;
}
// only allocate a fast track index if we were able to allocate a normal track name
- if (flags & IAudioFlinger::TRACK_FAST) {
+ if (flags & AUDIO_OUTPUT_FLAG_FAST) {
// FIXME: Not calling framesReadyIsCalledByMultipleThreads() exposes a potential
// race with setSyncEvent(). However, if we call it, we cannot properly start
// static fast tracks (SoundPool) immediately after stopping.
@@ -1133,7 +1132,7 @@
int uid)
: Track(playbackThread, NULL, AUDIO_STREAM_PATCH,
sampleRate, format, channelMask, frameCount,
- NULL, 0, AUDIO_SESSION_NONE, uid, IAudioFlinger::TRACK_DEFAULT,
+ NULL, 0, AUDIO_SESSION_NONE, uid, AUDIO_OUTPUT_FLAG_NONE,
TYPE_OUTPUT),
mActive(false), mSourceThread(sourceThread), mClientProxy(NULL)
{
@@ -1329,7 +1328,7 @@
audio_format_t format,
size_t frameCount,
void *buffer,
- IAudioFlinger::track_flags_t flags)
+ audio_output_flags_t flags)
: Track(playbackThread, NULL, streamType,
sampleRate, format, channelMask, frameCount,
buffer, 0, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
@@ -1468,19 +1467,19 @@
void *buffer,
audio_session_t sessionId,
int uid,
- IAudioFlinger::track_flags_t flags,
+ audio_input_flags_t flags,
track_type type)
: TrackBase(thread, client, sampleRate, format,
- channelMask, frameCount, buffer, sessionId, uid,
- flags, false /*isOut*/,
+ channelMask, frameCount, buffer, sessionId, uid, false /*isOut*/,
(type == TYPE_DEFAULT) ?
- ((flags & IAudioFlinger::TRACK_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
+ ((flags & AUDIO_INPUT_FLAG_FAST) ? ALLOC_PIPE : ALLOC_CBLK) :
((buffer == NULL) ? ALLOC_LOCAL : ALLOC_NONE),
type),
mOverflow(false),
mFramesToDrop(0),
mResamplerBufferProvider(NULL), // initialize in case of early constructor exit
- mRecordBufferConverter(NULL)
+ mRecordBufferConverter(NULL),
+ mFlags(flags)
{
if (mCblk == NULL) {
return;
@@ -1505,7 +1504,7 @@
mResamplerBufferProvider = new ResamplerBufferProvider(this);
- if (flags & IAudioFlinger::TRACK_FAST) {
+ if (flags & AUDIO_INPUT_FLAG_FAST) {
ALOG_ASSERT(thread->mFastTrackAvail);
thread->mFastTrackAvail = false;
}
@@ -1664,7 +1663,7 @@
audio_format_t format,
size_t frameCount,
void *buffer,
- IAudioFlinger::track_flags_t flags)
+ audio_input_flags_t flags)
: RecordTrack(recordThread, NULL, sampleRate, format, channelMask, frameCount,
buffer, AUDIO_SESSION_NONE, getuid(), flags, TYPE_PATCH),
mProxy(new ClientProxy(mCblk, mBuffer, frameCount, mFrameSize, false, true))
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 0a00368..5d64e44 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1499,6 +1499,8 @@
profileFlags);
if (profile != 0) {
break; // success
+ } else if (profileFlags & AUDIO_INPUT_FLAG_RAW) {
+ profileFlags = (audio_input_flags_t) (profileFlags & ~AUDIO_INPUT_FLAG_RAW); // retry
} else if (profileFlags != AUDIO_INPUT_FLAG_NONE) {
profileFlags = AUDIO_INPUT_FLAG_NONE; // retry
} else { // fail
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index dbec34e..a7fe5e7 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -338,13 +338,15 @@
status_t err = mDevice->configureStreams(isConstrainedHighSpeed);
if (err == BAD_VALUE) {
- res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
- "Camera %d: Unsupported set of inputs/outputs provided",
+ String8 msg = String8::format("Camera %d: Unsupported set of inputs/outputs provided",
mCameraId);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ res = STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
} else if (err != OK) {
- res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
- "Camera %d: Error configuring streams: %s (%d)",
+ String8 msg = String8::format("Camera %d: Error configuring streams: %s (%d)",
mCameraId, strerror(-err), err);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ res = STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
return res;
@@ -365,6 +367,7 @@
bool isInput = false;
ssize_t index = NAME_NOT_FOUND;
+ ssize_t dIndex = NAME_NOT_FOUND;
if (mInputStream.configured && mInputStream.id == streamId) {
isInput = true;
@@ -378,10 +381,19 @@
}
if (index == NAME_NOT_FOUND) {
- String8 msg = String8::format("Camera %d: Invalid stream ID (%d) specified, no such "
- "stream created yet", mCameraId, streamId);
- ALOGW("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ // See if this stream is one of the deferred streams.
+ for (size_t i = 0; i < mDeferredStreams.size(); ++i) {
+ if (streamId == mDeferredStreams[i]) {
+ dIndex = i;
+ break;
+ }
+ }
+ if (dIndex == NAME_NOT_FOUND) {
+ String8 msg = String8::format("Camera %d: Invalid stream ID (%d) specified, no such"
+ " stream created yet", mCameraId, streamId);
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
}
}
@@ -396,8 +408,10 @@
} else {
if (isInput) {
mInputStream.configured = false;
- } else {
+ } else if (index != NAME_NOT_FOUND) {
mStreamMap.removeItemsAt(index);
+ } else {
+ mDeferredStreams.removeItemsAt(dIndex);
}
}
@@ -416,14 +430,30 @@
Mutex::Autolock icl(mBinderSerializationLock);
sp<IGraphicBufferProducer> bufferProducer = outputConfiguration.getGraphicBufferProducer();
- if (bufferProducer == NULL) {
- ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
+ bool deferredConsumer = bufferProducer == NULL;
+ int surfaceType = outputConfiguration.getSurfaceType();
+ bool validSurfaceType = ((surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) ||
+ (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_TEXTURE));
+ if (deferredConsumer && !validSurfaceType) {
+ ALOGE("%s: Target surface is invalid: bufferProducer = %p, surfaceType = %d.",
+ __FUNCTION__, bufferProducer.get(), surfaceType);
return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
}
+
if (!mDevice.get()) {
return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
}
+ int width, height, format;
+ int32_t consumerUsage;
+ android_dataspace dataSpace;
+ status_t err;
+
+ // Create stream for deferred surface case.
+ if (deferredConsumer) {
+ return createDeferredSurfaceStreamLocked(outputConfiguration, newStreamId);
+ }
+
// Don't create multiple streams for the same target surface
{
ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
@@ -435,13 +465,10 @@
}
}
- status_t err;
-
// HACK b/10949105
// Query consumer usage bits to set async operation mode for
// GLConsumer using controlledByApp parameter.
bool useAsync = false;
- int32_t consumerUsage;
if ((err = bufferProducer->query(NATIVE_WINDOW_CONSUMER_USAGE_BITS,
&consumerUsage)) != OK) {
String8 msg = String8::format("Camera %d: Failed to query Surface consumer usage: %s (%d)",
@@ -450,8 +477,8 @@
return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
}
if (consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) {
- ALOGW("%s: Camera %d: Forcing asynchronous mode for stream",
- __FUNCTION__, mCameraId);
+ ALOGW("%s: Camera %d with consumer usage flag: 0x%x: Forcing asynchronous mode for stream",
+ __FUNCTION__, mCameraId, consumerUsage);
useAsync = true;
}
@@ -467,9 +494,6 @@
sp<Surface> surface = new Surface(bufferProducer, useAsync);
ANativeWindow *anw = surface.get();
- int width, height, format;
- android_dataspace dataSpace;
-
if ((err = anw->query(anw, NATIVE_WINDOW_WIDTH, &width)) != OK) {
String8 msg = String8::format("Camera %d: Failed to query Surface width: %s (%d)",
mCameraId, strerror(-err), err);
@@ -526,29 +550,12 @@
} else {
mStreamMap.add(binder, streamId);
- ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
- __FUNCTION__, mCameraId, streamId);
+ ALOGV("%s: Camera %d: Successfully created a new stream ID %d for output surface"
+ " (%d x %d) with format 0x%x.",
+ __FUNCTION__, mCameraId, streamId, width, height, format);
- /**
- * Set the stream transform flags to automatically
- * rotate the camera stream for preview use cases.
- */
- int32_t transform = 0;
- err = getRotationTransformLocked(&transform);
-
- if (err != OK) {
- // Error logged by getRotationTransformLocked.
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
- "Unable to calculate rotation transform for new stream");
- }
-
- err = mDevice->setStreamTransform(streamId, transform);
- if (err != OK) {
- String8 msg = String8::format("Failed to set stream transform (stream id %d)",
- streamId);
- ALOGE("%s: %s", __FUNCTION__, msg.string());
- return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
- }
+ // Set transform flags to ensure preview to be rotated correctly.
+ res = setStreamTransformLocked(streamId);
*newStreamId = streamId;
}
@@ -556,6 +563,84 @@
return res;
}
+binder::Status CameraDeviceClient::createDeferredSurfaceStreamLocked(
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration,
+ /*out*/
+ int* newStreamId) {
+ int width, height, format, surfaceType;
+ int32_t consumerUsage;
+ android_dataspace dataSpace;
+ status_t err;
+ binder::Status res;
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ // Infer the surface info for deferred surface stream creation.
+ width = outputConfiguration.getWidth();
+ height = outputConfiguration.getHeight();
+ surfaceType = outputConfiguration.getSurfaceType();
+ format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ dataSpace = android_dataspace_t::HAL_DATASPACE_UNKNOWN;
+ // Hardcode consumer usage flags: SurfaceView--0x900, SurfaceTexture--0x100.
+ consumerUsage = GraphicBuffer::USAGE_HW_TEXTURE;
+ if (surfaceType == OutputConfiguration::SURFACE_TYPE_SURFACE_VIEW) {
+ consumerUsage |= GraphicBuffer::USAGE_HW_COMPOSER;
+ }
+ int streamId = camera3::CAMERA3_STREAM_ID_INVALID;
+ err = mDevice->createStream(/*surface*/nullptr, width, height, format, dataSpace,
+ static_cast<camera3_stream_rotation_t>(outputConfiguration.getRotation()),
+ &streamId, outputConfiguration.getSurfaceSetID(), consumerUsage);
+
+ if (err != OK) {
+ res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+ "Camera %d: Error creating output stream (%d x %d, fmt %x, dataSpace %x): %s (%d)",
+ mCameraId, width, height, format, dataSpace, strerror(-err), err);
+ } else {
+ // Can not add streamId to mStreamMap here, as the surface is deferred. Add it to
+ // a separate list to track. Once the deferred surface is set, this id will be
+ // relocated to mStreamMap.
+ mDeferredStreams.push_back(streamId);
+
+ ALOGV("%s: Camera %d: Successfully created a new stream ID %d for a deferred surface"
+ " (%d x %d) stream with format 0x%x.",
+ __FUNCTION__, mCameraId, streamId, width, height, format);
+
+ // Set transform flags to ensure preview to be rotated correctly.
+ res = setStreamTransformLocked(streamId);
+
+ *newStreamId = streamId;
+ }
+ return res;
+}
+
+binder::Status CameraDeviceClient::setStreamTransformLocked(int streamId) {
+ int32_t transform = 0;
+ status_t err;
+ binder::Status res;
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ err = getRotationTransformLocked(&transform);
+ if (err != OK) {
+ // Error logged by getRotationTransformLocked.
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION,
+ "Unable to calculate rotation transform for new stream");
+ }
+
+ err = mDevice->setStreamTransform(streamId, transform);
+ if (err != OK) {
+ String8 msg = String8::format("Failed to set stream transform (stream id %d)",
+ streamId);
+ ALOGE("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_INVALID_OPERATION, msg.string());
+ }
+
+ return res;
+}
binder::Status CameraDeviceClient::createInputStream(
int width, int height, int format,
@@ -934,6 +1019,76 @@
return res;
}
+binder::Status CameraDeviceClient::setDeferredConfiguration(int32_t streamId,
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration) {
+ ATRACE_CALL();
+
+ binder::Status res;
+ if (!(res = checkPidStatus(__FUNCTION__)).isOk()) return res;
+
+ Mutex::Autolock icl(mBinderSerializationLock);
+
+ sp<IGraphicBufferProducer> bufferProducer = outputConfiguration.getGraphicBufferProducer();
+
+ // Client code should guarantee that the surface is from SurfaceView or SurfaceTexture.
+ if (bufferProducer == NULL) {
+ ALOGE("%s: bufferProducer must not be null", __FUNCTION__);
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, "Target Surface is invalid");
+ }
+ // Check if this stram id is one of the deferred streams
+ ssize_t index = NAME_NOT_FOUND;
+ for (size_t i = 0; i < mDeferredStreams.size(); i++) {
+ if (streamId == mDeferredStreams[i]) {
+ index = i;
+ break;
+ }
+ }
+ if (index == NAME_NOT_FOUND) {
+ String8 msg = String8::format("Camera %d: deferred surface is set to a unknown stream"
+ "(ID %d)", mCameraId, streamId);
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ILLEGAL_ARGUMENT, msg.string());
+ }
+
+ if (!mDevice.get()) {
+ return STATUS_ERROR(CameraService::ERROR_DISCONNECTED, "Camera device no longer alive");
+ }
+
+ // Don't create multiple streams for the same target surface
+ {
+ ssize_t index = mStreamMap.indexOfKey(IInterface::asBinder(bufferProducer));
+ if (index != NAME_NOT_FOUND) {
+ String8 msg = String8::format("Camera %d: Surface already has a stream created "
+ " for it (ID %zd)", mCameraId, index);
+ ALOGW("%s: %s", __FUNCTION__, msg.string());
+ return STATUS_ERROR(CameraService::ERROR_ALREADY_EXISTS, msg.string());
+ }
+ }
+
+ status_t err;
+
+ // Always set to async, as we know the deferred surface is for preview streaming.
+ sp<Surface> consumerSurface = new Surface(bufferProducer, /*useAsync*/true);
+
+ // Finish the deferred stream configuration with the surface.
+ err = mDevice->setConsumerSurface(streamId, consumerSurface);
+ if (err == OK) {
+ sp<IBinder> binder = IInterface::asBinder(bufferProducer);
+ mStreamMap.add(binder, streamId);
+ mDeferredStreams.removeItemsAt(index);
+ } else if (err == NO_INIT) {
+ res = STATUS_ERROR_FMT(CameraService::ERROR_ILLEGAL_ARGUMENT,
+ "Camera %d: Deferred surface is invalid: %s (%d)",
+ mCameraId, strerror(-err), err);
+ } else {
+ res = STATUS_ERROR_FMT(CameraService::ERROR_INVALID_OPERATION,
+ "Camera %d: Error setting output stream deferred surface: %s (%d)",
+ mCameraId, strerror(-err), err);
+ }
+
+ return res;
+}
+
status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
return BasicClient::dump(fd, args);
}
@@ -959,6 +1114,11 @@
for (size_t i = 0; i < mStreamMap.size(); i++) {
result.appendFormat(" Stream %d\n", mStreamMap.valueAt(i));
}
+ } else if (!mDeferredStreams.isEmpty()) {
+ result.append(" Current deferred surface output stream IDs:\n");
+ for (auto& streamId : mDeferredStreams) {
+ result.appendFormat(" Stream %d\n", streamId);
+ }
} else {
result.append(" No output streams configured.\n");
}
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.h b/services/camera/libcameraservice/api2/CameraDeviceClient.h
index d792b7d..dde23fb 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.h
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.h
@@ -131,6 +131,10 @@
// Prepare stream by preallocating up to maxCount of its buffers
virtual binder::Status prepare2(int32_t maxCount, int32_t streamId);
+ // Set the deferred surface for a stream.
+ virtual binder::Status setDeferredConfiguration(int32_t streamId,
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration);
+
/**
* Interface used by CameraService
*/
@@ -188,6 +192,15 @@
// Find the square of the euclidean distance between two points
static int64_t euclidDistSquare(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
+ // Create an output stream with surface deferred for future.
+ binder::Status createDeferredSurfaceStreamLocked(
+ const hardware::camera2::params::OutputConfiguration &outputConfiguration,
+ int* newStreamId = NULL);
+
+ // Set the stream transform flags to automatically rotate the camera stream for preview use
+ // cases.
+ binder::Status setStreamTransformLocked(int streamId);
+
// Find the closest dimensions for a given format in available stream configurations with
// a width <= ROUNDING_WIDTH_CAP
static const int32_t ROUNDING_WIDTH_CAP = 1920;
@@ -213,6 +226,10 @@
int32_t mRequestIdCounter;
+ // The list of output streams whose surfaces are deferred. We have to track them separately
+ // as there are no surfaces available and can not be put into mStreamMap. Once the deferred
+ // Surface is configured, the stream id will be moved to mStreamMap.
+ Vector<int32_t> mDeferredStreams;
};
}; // namespace android
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index 35ec531..8707f2a 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -110,7 +110,8 @@
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,
- int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID) = 0;
+ int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
+ uint32_t consumerUsage = 0) = 0;
/**
* Create an input stream of width, height, and format.
@@ -312,6 +313,12 @@
* Get the HAL device version.
*/
virtual uint32_t getDeviceVersion() = 0;
+
+ /**
+ * Set the deferred consumer surface and finish the rest of the stream configuration.
+ */
+ virtual status_t setConsumerSurface(int streamId, sp<Surface> consumer) = 0;
+
};
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 96f9338..bbe7317 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -990,12 +990,13 @@
status_t Camera3Device::createStream(sp<Surface> consumer,
uint32_t width, uint32_t height, int format, android_dataspace dataSpace,
- camera3_stream_rotation_t rotation, int *id, int streamSetId) {
+ camera3_stream_rotation_t rotation, int *id, int streamSetId, uint32_t consumerUsage) {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
Mutex::Autolock l(mLock);
- ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d",
- mId, mNextStreamId, width, height, format, dataSpace, rotation);
+ ALOGV("Camera %d: Creating new stream %d: %d x %d, format %d, dataspace %d rotation %d"
+ " consumer usage 0x%x", mId, mNextStreamId, width, height, format, dataSpace, rotation,
+ consumerUsage);
status_t res;
bool wasActive = false;
@@ -1032,6 +1033,19 @@
if (mDeviceVersion <= CAMERA_DEVICE_API_VERSION_3_2) {
streamSetId = CAMERA3_STREAM_SET_ID_INVALID;
}
+
+ // HAL3.1 doesn't support deferred consumer stream creation as it requires buffer registration
+ // which requires a consumer surface to be available.
+ if (consumer == nullptr && mDeviceVersion < CAMERA_DEVICE_API_VERSION_3_2) {
+ ALOGE("HAL3.1 doesn't support deferred consumer stream creation");
+ return BAD_VALUE;
+ }
+
+ if (consumer == nullptr && format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ ALOGE("Deferred consumer stream creation only support IMPLEMENTATION_DEFINED format");
+ return BAD_VALUE;
+ }
+
// Use legacy dataspace values for older HALs
if (mDeviceVersion <= CAMERA_DEVICE_API_VERSION_3_3) {
dataSpace = mapToLegacyDataspace(dataSpace);
@@ -1063,6 +1077,10 @@
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, rawOpaqueBufferSize, format, dataSpace, rotation,
mTimestampOffset, streamSetId);
+ } else if (consumer == nullptr) {
+ newStream = new Camera3OutputStream(mNextStreamId,
+ width, height, format, consumerUsage, dataSpace, rotation,
+ mTimestampOffset, streamSetId);
} else {
newStream = new Camera3OutputStream(mNextStreamId, consumer,
width, height, format, dataSpace, rotation,
@@ -1722,6 +1740,44 @@
}
}
+status_t Camera3Device::setConsumerSurface(int streamId, sp<Surface> consumer) {
+ ATRACE_CALL();
+ ALOGV("%s: Camera %d: set consumer surface for stream %d", __FUNCTION__, mId, streamId);
+ Mutex::Autolock il(mInterfaceLock);
+ Mutex::Autolock l(mLock);
+
+ if (consumer == nullptr) {
+ CLOGE("Null consumer is passed!");
+ return BAD_VALUE;
+ }
+
+ ssize_t idx = mOutputStreams.indexOfKey(streamId);
+ if (idx == NAME_NOT_FOUND) {
+ CLOGE("Stream %d is unknown", streamId);
+ return idx;
+ }
+ sp<Camera3OutputStreamInterface> stream = mOutputStreams[idx];
+ status_t res = stream->setConsumer(consumer);
+ if (res != OK) {
+ CLOGE("Stream %d set consumer failed (error %d %s) ", streamId, res, strerror(-res));
+ return res;
+ }
+
+ if (!stream->isConfiguring()) {
+ CLOGE("Stream %d was already fully configured.", streamId);
+ return INVALID_OPERATION;
+ }
+
+ res = stream->finishConfiguration(mHal3Device);
+ if (res != OK) {
+ SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
+ stream->getId(), strerror(-res), res);
+ return res;
+ }
+
+ return OK;
+}
+
/**
* Camera3Device private methods
*/
@@ -1781,6 +1837,13 @@
sp<Camera3OutputStreamInterface> stream =
mOutputStreams.editValueAt(idx);
+ // It is illegal to include a deferred consumer output stream into a request
+ if (stream->isConsumerConfigurationDeferred()) {
+ CLOGE("Stream %d hasn't finished configuration yet due to deferred consumer",
+ stream->getId());
+ return NULL;
+ }
+
// Lazy completion of stream configuration (allocation/registration)
// on first use
if (stream->isConfiguring()) {
@@ -1948,7 +2011,7 @@
for (size_t i = 0; i < mOutputStreams.size(); i++) {
sp<Camera3OutputStreamInterface> outputStream =
mOutputStreams.editValueAt(i);
- if (outputStream->isConfiguring()) {
+ if (outputStream->isConfiguring() && !outputStream->isConsumerConfigurationDeferred()) {
res = outputStream->finishConfiguration(mHal3Device);
if (res != OK) {
CLOGE("Can't finish configuring output stream %d: %s (%d)",
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 2aca57d..fe5f217 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -95,11 +95,14 @@
// Actual stream creation/deletion is delayed until first request is submitted
// If adding streams while actively capturing, will pause device before adding
- // stream, reconfiguring device, and unpausing.
+ // stream, reconfiguring device, and unpausing. If the client create a stream
+ // with nullptr consumer surface, the client must then call setConsumer()
+ // and finish the stream configuration before starting output streaming.
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,
- int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID);
+ int streamSetId = camera3::CAMERA3_STREAM_SET_ID_INVALID,
+ uint32_t consumerUsage = 0);
virtual status_t createInputStream(
uint32_t width, uint32_t height, int format,
int *id);
@@ -160,6 +163,12 @@
// Methods called by subclasses
void notifyStatus(bool idle); // updates from StatusTracker
+ /**
+ * Set the deferred consumer surface to the output stream and finish the deferred
+ * consumer configuration.
+ */
+ virtual status_t setConsumerSurface(int streamId, sp<Surface> consumer);
+
private:
static const size_t kDumpLockAttempts = 10;
static const size_t kDumpSleepDuration = 100000; // 0.10 sec
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
index 6354ef7..5123785 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.cpp
@@ -103,6 +103,15 @@
return false;
}
+bool Camera3DummyStream::isConsumerConfigurationDeferred() const {
+ return false;
+}
+
+status_t Camera3DummyStream::setConsumer(sp<Surface> consumer) {
+ ALOGE("%s: Stream %d: Dummy stream doesn't support set consumer surface %p!",
+ __FUNCTION__, mId, consumer.get());
+ return INVALID_OPERATION;
+}
}; // namespace camera3
}; // namespace android
diff --git a/services/camera/libcameraservice/device3/Camera3DummyStream.h b/services/camera/libcameraservice/device3/Camera3DummyStream.h
index 7b48daa..639619e 100644
--- a/services/camera/libcameraservice/device3/Camera3DummyStream.h
+++ b/services/camera/libcameraservice/device3/Camera3DummyStream.h
@@ -61,6 +61,16 @@
*/
bool isVideoStream() const;
+ /**
+ * Return if the consumer configuration of this stream is deferred.
+ */
+ virtual bool isConsumerConfigurationDeferred() const;
+
+ /**
+ * Set the consumer surface to the output stream.
+ */
+ virtual status_t setConsumer(sp<Surface> consumer);
+
protected:
/**
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
index d09951a..bc8f631 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.cpp
@@ -42,7 +42,8 @@
mTransform(0),
mTraceFirstBuffer(true),
mUseBufferManager(false),
- mTimestampOffset(timestampOffset) {
+ mTimestampOffset(timestampOffset),
+ mConsumerUsage(0) {
if (mConsumer == NULL) {
ALOGE("%s: Consumer is NULL!", __FUNCTION__);
@@ -66,7 +67,8 @@
mTraceFirstBuffer(true),
mUseMonoTimestamp(false),
mUseBufferManager(false),
- mTimestampOffset(timestampOffset) {
+ mTimestampOffset(timestampOffset),
+ mConsumerUsage(0) {
if (format != HAL_PIXEL_FORMAT_BLOB && format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
ALOGE("%s: Bad format for size-only stream: %d", __FUNCTION__,
@@ -84,6 +86,39 @@
}
}
+Camera3OutputStream::Camera3OutputStream(int id,
+ uint32_t width, uint32_t height, int format,
+ uint32_t consumerUsage, android_dataspace dataSpace,
+ camera3_stream_rotation_t rotation, nsecs_t timestampOffset, int setId) :
+ Camera3IOStreamBase(id, CAMERA3_STREAM_OUTPUT, width, height,
+ /*maxSize*/0, format, dataSpace, rotation, setId),
+ mConsumer(nullptr),
+ mTransform(0),
+ mTraceFirstBuffer(true),
+ mUseBufferManager(false),
+ mTimestampOffset(timestampOffset),
+ mConsumerUsage(consumerUsage) {
+ // Deferred consumer only support preview surface format now.
+ if (format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
+ ALOGE("%s: Deferred consumer only supports IMPLEMENTATION_DEFINED format now!",
+ __FUNCTION__);
+ mState = STATE_ERROR;
+ }
+
+ // Sanity check for the consumer usage flag.
+ if ((consumerUsage & GraphicBuffer::USAGE_HW_TEXTURE) == 0 &&
+ (consumerUsage & GraphicBuffer::USAGE_HW_COMPOSER) == 0) {
+ ALOGE("%s: Deferred consumer usage flag is illegal (0x%x)!", __FUNCTION__, consumerUsage);
+ mState = STATE_ERROR;
+ }
+
+ mConsumerName = String8("Deferred");
+ if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
+ mBufferReleasedListener = new BufferReleasedListener(this);
+ }
+
+}
+
Camera3OutputStream::Camera3OutputStream(int id, camera3_stream_type_t type,
uint32_t width, uint32_t height,
int format,
@@ -96,7 +131,8 @@
mTransform(0),
mTraceFirstBuffer(true),
mUseMonoTimestamp(false),
- mUseBufferManager(false) {
+ mUseBufferManager(false),
+ mConsumerUsage(0) {
if (setId > CAMERA3_STREAM_SET_ID_INVALID) {
mBufferReleasedListener = new BufferReleasedListener(this);
@@ -475,11 +511,16 @@
return res;
}
+ // Stream configuration was not finished (can only be in STATE_IN_CONFIG or STATE_CONSTRUCTED
+ // state), don't need change the stream state, return OK.
+ if (mConsumer == nullptr) {
+ return OK;
+ }
+
ALOGV("%s: disconnecting stream %d from native window", __FUNCTION__, getId());
res = native_window_api_disconnect(mConsumer.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
@@ -521,6 +562,12 @@
status_t res;
int32_t u = 0;
+ if (mConsumer == nullptr) {
+ // mConsumerUsage was sanitized before the Camera3OutputStream was constructed.
+ *usage = mConsumerUsage;
+ return OK;
+ }
+
res = static_cast<ANativeWindow*>(mConsumer.get())->query(mConsumer.get(),
NATIVE_WINDOW_CONSUMER_USAGE_BITS, &u);
@@ -556,7 +603,7 @@
status_t Camera3OutputStream::setBufferManager(sp<Camera3BufferManager> bufferManager) {
Mutex::Autolock l(mLock);
if (mState != STATE_CONSTRUCTED) {
- ALOGE("%s: this method can only be called when stream in in CONSTRUCTED state.",
+ ALOGE("%s: this method can only be called when stream in CONSTRUCTED state.",
__FUNCTION__);
return INVALID_OPERATION;
}
@@ -622,6 +669,26 @@
return OK;
}
+bool Camera3OutputStream::isConsumerConfigurationDeferred() const {
+ Mutex::Autolock l(mLock);
+ return mConsumer == nullptr;
+}
+
+status_t Camera3OutputStream::setConsumer(sp<Surface> consumer) {
+ if (consumer == nullptr) {
+ ALOGE("%s: it's illegal to set a null consumer surface!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ if (mConsumer != nullptr) {
+ ALOGE("%s: consumer surface was already set!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+
+ mConsumer = consumer;
+ return OK;
+}
+
bool Camera3OutputStream::isConsumedByHWComposer() const {
uint32_t usage = 0;
status_t res = getEndpointUsage(&usage);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStream.h b/services/camera/libcameraservice/device3/Camera3OutputStream.h
index 7d28b05..5507cfc 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStream.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStream.h
@@ -94,6 +94,16 @@
android_dataspace dataSpace, camera3_stream_rotation_t rotation,
nsecs_t timestampOffset, int setId = CAMERA3_STREAM_SET_ID_INVALID);
+ /**
+ * Set up a stream with deferred consumer for formats that have 2 dimensions, such as
+ * RAW and YUV. The consumer must be set before using this stream for output. A valid
+ * stream set id needs to be set to support buffer sharing between multiple streams.
+ */
+ Camera3OutputStream(int id, uint32_t width, uint32_t height, int format,
+ uint32_t consumerUsage, android_dataspace dataSpace,
+ camera3_stream_rotation_t rotation, nsecs_t timestampOffset,
+ int setId = CAMERA3_STREAM_SET_ID_INVALID);
+
virtual ~Camera3OutputStream();
/**
@@ -117,6 +127,16 @@
*/
bool isConsumedByHWComposer() const;
+ /**
+ * Return if the consumer configuration of this stream is deferred.
+ */
+ virtual bool isConsumerConfigurationDeferred() const;
+
+ /**
+ * Set the consumer surface to the output stream.
+ */
+ virtual status_t setConsumer(sp<Surface> consumer);
+
class BufferReleasedListener : public BnProducerListener {
public:
BufferReleasedListener(wp<Camera3OutputStream> parent) : mParent(parent) {}
@@ -159,6 +179,7 @@
virtual status_t disconnectLocked();
sp<Surface> mConsumer;
+
private:
int mTransform;
@@ -195,6 +216,12 @@
nsecs_t mTimestampOffset;
/**
+ * Consumer end point usage flag set by the constructor for the deferred
+ * consumer case.
+ */
+ uint32_t mConsumerUsage;
+
+ /**
* Internal Camera3Stream interface
*/
virtual status_t getBufferLocked(camera3_stream_buffer *buffer);
diff --git a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
index 50dce55..3f83c89 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputStreamInterface.h
@@ -41,6 +41,16 @@
virtual bool isVideoStream() const = 0;
/**
+ * Return if the consumer configuration of this stream is deferred.
+ */
+ virtual bool isConsumerConfigurationDeferred() const = 0;
+
+ /**
+ * Set the consumer surface to the output stream.
+ */
+ virtual status_t setConsumer(sp<Surface> consumer) = 0;
+
+ /**
* Detach an unused buffer from the stream.
*
* buffer must be non-null; fenceFd may null, and if it is non-null, but
@@ -49,7 +59,6 @@
*
*/
virtual status_t detachBuffer(sp<GraphicBuffer>* buffer, int* fenceFd) = 0;
-
};
} // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 96d62d4..3ffd9d1 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -55,7 +55,7 @@
mMaxSize(maxSize),
mState(STATE_CONSTRUCTED),
mStatusId(StatusTracker::NO_STATUS_ID),
- mStreamUnpreparable(false),
+ mStreamUnpreparable(true),
mOldUsage(0),
mOldMaxBuffers(0),
mPrepared(false),
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 0755700..1ff215d 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -175,7 +175,8 @@
* OK on a successful configuration
* NO_INIT in case of a serious error from the HAL device
* NO_MEMORY in case of an error registering buffers
- * INVALID_OPERATION in case connecting to the consumer failed
+ * INVALID_OPERATION in case connecting to the consumer failed or consumer
+ * doesn't exist yet.
*/
status_t finishConfiguration(camera3_device *hal3Device);