Merge "mediaresourcemanager: add ServiceLog to track the calling history for dumpsys." into mnc-dev
diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp
index 0029aec..36fa3b5 100644
--- a/cmds/stagefright/muxer.cpp
+++ b/cmds/stagefright/muxer.cpp
@@ -142,8 +142,13 @@
CHECK_EQ(err, (status_t)OK);
ssize_t newTrackIndex = muxer->addTrack(format);
- CHECK_GE(newTrackIndex, 0);
- trackIndexMap.add(i, newTrackIndex);
+ if (newTrackIndex < 0) {
+ fprintf(stderr, "%s track (%zu) unsupported by muxer\n",
+ isAudio ? "audio" : "video",
+ i);
+ } else {
+ trackIndexMap.add(i, newTrackIndex);
+ }
}
int64_t muxerStartTimeUs = ALooper::GetNowUs();
@@ -162,7 +167,12 @@
ALOGV("saw input eos, err %d", err);
sawInputEOS = true;
break;
+ } else if (trackIndexMap.indexOfKey(trackIndex) < 0) {
+ // ALOGV("skipping input from unsupported track %zu", trackIndex);
+ extractor->advance();
+ continue;
} else {
+ // ALOGV("reading sample from track index %zu\n", trackIndex);
err = extractor->readSampleData(newBuffer);
CHECK_EQ(err, (status_t)OK);
diff --git a/include/media/AudioIoDescriptor.h b/include/media/AudioIoDescriptor.h
index 2437901..c94b738 100644
--- a/include/media/AudioIoDescriptor.h
+++ b/include/media/AudioIoDescriptor.h
@@ -33,12 +33,31 @@
class AudioIoDescriptor : public RefBase {
public:
AudioIoDescriptor() :
+ mIoHandle(AUDIO_IO_HANDLE_NONE),
mSamplingRate(0), mFormat(AUDIO_FORMAT_DEFAULT), mChannelMask(AUDIO_CHANNEL_NONE),
- mFrameCount(0), mLatency(0) {}
+ mFrameCount(0), mLatency(0)
+ {
+ memset(&mPatch, 0, sizeof(struct audio_patch));
+ }
virtual ~AudioIoDescriptor() {}
+ audio_port_handle_t getDeviceId() {
+ if (mPatch.num_sources != 0 && mPatch.num_sinks != 0) {
+ if (mPatch.sources[0].type == AUDIO_PORT_TYPE_MIX) {
+ // this is an output mix
+ // FIXME: the API only returns the first device in case of multiple device selection
+ return mPatch.sinks[0].id;
+ } else {
+ // this is an input mix
+ return mPatch.sources[0].id;
+ }
+ }
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+
audio_io_handle_t mIoHandle;
+ struct audio_patch mPatch;
uint32_t mSamplingRate;
audio_format_t mFormat;
audio_channel_mask_t mChannelMask;
diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h
index b743c11..c4c7b0e 100644
--- a/include/media/AudioRecord.h
+++ b/include/media/AudioRecord.h
@@ -178,6 +178,8 @@
int sessionId = AUDIO_SESSION_ALLOCATE,
transfer_type transferType = TRANSFER_DEFAULT,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
+ int uid = -1,
+ pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL);
/* Terminates the AudioRecord and unregisters it from AudioFlinger.
@@ -214,6 +216,8 @@
int sessionId = AUDIO_SESSION_ALLOCATE,
transfer_type transferType = TRANSFER_DEFAULT,
audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE,
+ int uid = -1,
+ pid_t pid = -1,
const audio_attributes_t* pAttributes = NULL);
/* Result of constructing the AudioRecord. This must be checked for successful initialization
@@ -390,6 +394,39 @@
* TODO Document this method.
*/
audio_port_handle_t getInputDevice();
+
+ /* Returns the ID of the audio device actually used by the input to which this AudioRecord
+ * is attached.
+ * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input.
+ *
+ * Parameters:
+ * none.
+ */
+ audio_port_handle_t getRoutedDeviceId();
+
+ /* Add an AudioDeviceCallback. The caller will be notified when the audio device
+ * to which this AudioRecord is routed is updated.
+ * Replaces any previously installed callback.
+ * Parameters:
+ * callback: The callback interface
+ * Returns NO_ERROR if successful.
+ * INVALID_OPERATION if the same callback is already installed.
+ * NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+ * BAD_VALUE if the callback is NULL
+ */
+ status_t addAudioDeviceCallback(
+ const sp<AudioSystem::AudioDeviceCallback>& callback);
+
+ /* remove an AudioDeviceCallback.
+ * Parameters:
+ * callback: The callback interface
+ * Returns NO_ERROR if successful.
+ * INVALID_OPERATION if the callback is not installed
+ * BAD_VALUE if the callback is NULL
+ */
+ status_t removeAudioDeviceCallback(
+ const sp<AudioSystem::AudioDeviceCallback>& callback);
+
private:
/* If nonContig is non-NULL, it is an output parameter that will be set to the number of
* additional non-contiguous frames that are predicted to be available immediately,
@@ -577,11 +614,14 @@
sp<DeathNotifier> mDeathNotifier;
uint32_t mSequence; // incremented for each new IAudioRecord attempt
+ int mClientUid;
+ pid_t mClientPid;
audio_attributes_t mAttributes;
// For Device Selection API
// a value of AUDIO_PORT_HANDLE_NONE indicated default (AudioPolicyManager) routing.
audio_port_handle_t mSelectedDeviceId;
+ sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
};
}; // namespace android
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 0cbcdb1..3241e9c 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -332,8 +332,26 @@
};
- static status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack);
- static status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack);
+ static status_t addAudioPortCallback(const sp<AudioPortCallback>& callback);
+ static status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback);
+
+ class AudioDeviceCallback : public RefBase
+ {
+ public:
+
+ AudioDeviceCallback() {}
+ virtual ~AudioDeviceCallback() {}
+
+ virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+ audio_port_handle_t deviceId) = 0;
+ };
+
+ static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ audio_io_handle_t audioIo);
+ static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ audio_io_handle_t audioIo);
+
+ static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
private:
@@ -359,10 +377,20 @@
// values for output/input parameters up-to-date in client process
virtual void ioConfigChanged(audio_io_config_event event,
const sp<AudioIoDescriptor>& ioDesc);
+
+
+ status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ audio_io_handle_t audioIo);
+ status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+ audio_io_handle_t audioIo);
+
+ audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
+
private:
Mutex mLock;
- DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors;
-
+ DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> > mIoDescriptors;
+ DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > >
+ mAudioDeviceCallbacks;
// cached values for recording getInputBufferSize() queries
size_t mInBuffSize; // zero indicates cache is invalid
uint32_t mInSamplingRate;
@@ -377,8 +405,8 @@
AudioPolicyServiceClient() {
}
- status_t addAudioPortCallback(const sp<AudioPortCallback>& callBack);
- status_t removeAudioPortCallback(const sp<AudioPortCallback>& callBack);
+ status_t addAudioPortCallback(const sp<AudioPortCallback>& callback);
+ status_t removeAudioPortCallback(const sp<AudioPortCallback>& callback);
// DeathRecipient
virtual void binderDied(const wp<IBinder>& who);
@@ -393,6 +421,9 @@
Vector <sp <AudioPortCallback> > mAudioPortCallbacks;
};
+ static const sp<AudioFlingerClient> getAudioFlingerClient();
+ static sp<AudioIoDescriptor> getIoDescriptor(audio_io_handle_t ioHandle);
+
static sp<AudioFlingerClient> gAudioFlingerClient;
static sp<AudioPolicyServiceClient> gAudioPolicyServiceClient;
friend class AudioFlingerClient;
diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h
index 0ccd19e..458f4b4 100644
--- a/include/media/AudioTrack.h
+++ b/include/media/AudioTrack.h
@@ -510,7 +510,7 @@
*/
status_t setOutputDevice(audio_port_handle_t deviceId);
- /* Returns the ID of the audio device used for output of this AudioTrack.
+ /* Returns the ID of the audio device selected for this AudioTrack.
* A value of AUDIO_PORT_HANDLE_NONE indicates default (AudioPolicyManager) routing.
*
* Parameters:
@@ -518,6 +518,15 @@
*/
audio_port_handle_t getOutputDevice();
+ /* Returns the ID of the audio device actually used by the output to which this AudioTrack is
+ * attached.
+ * A value of AUDIO_PORT_HANDLE_NONE indicates the audio track is not attached to any output.
+ *
+ * Parameters:
+ * none.
+ */
+ audio_port_handle_t getRoutedDeviceId();
+
/* Returns the unique session ID associated with this track.
*
* Parameters:
@@ -664,6 +673,28 @@
*/
status_t getTimestamp(AudioTimestamp& timestamp);
+ /* Add an AudioDeviceCallback. The caller will be notified when the audio device to which this
+ * AudioTrack is routed is updated.
+ * Replaces any previously installed callback.
+ * Parameters:
+ * callback: The callback interface
+ * Returns NO_ERROR if successful.
+ * INVALID_OPERATION if the same callback is already installed.
+ * NO_INIT or PREMISSION_DENIED if AudioFlinger service is not reachable
+ * BAD_VALUE if the callback is NULL
+ */
+ status_t addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback);
+
+ /* remove an AudioDeviceCallback.
+ * Parameters:
+ * callback: The callback interface
+ * Returns NO_ERROR if successful.
+ * INVALID_OPERATION if the callback is not installed
+ * BAD_VALUE if the callback is NULL
+ */
+ status_t removeAudioDeviceCallback(
+ const sp<AudioSystem::AudioDeviceCallback>& callback);
+
protected:
/* copying audio tracks is not allowed */
AudioTrack(const AudioTrack& other);
@@ -885,6 +916,8 @@
uint32_t mSequence; // incremented for each new IAudioTrack attempt
int mClientUid;
pid_t mClientPid;
+
+ sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
};
class TimedAudioTrack : public AudioTrack
diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h
index 046345c..3f7fd09 100644
--- a/include/media/IAudioFlinger.h
+++ b/include/media/IAudioFlinger.h
@@ -89,6 +89,7 @@
size_t *pFrameCount,
track_flags_t *flags,
pid_t tid, // -1 means unused, otherwise must be valid non-0
+ int clientUid,
int *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h
index cdb923d..0a54df9 100644
--- a/include/media/stagefright/ACodec.h
+++ b/include/media/stagefright/ACodec.h
@@ -236,9 +236,6 @@
status_t freeBuffer(OMX_U32 portIndex, size_t i);
status_t handleSetSurface(const sp<Surface> &surface);
- status_t setNativeWindowSizeFormatAndUsage(
- ANativeWindow *nativeWindow /* nonnull */,
- int width, int height, int format, int rotation, int usage);
status_t setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */);
status_t configureOutputBuffersFromNativeWindow(
@@ -332,8 +329,6 @@
status_t initNativeWindow();
- status_t pushBlankBuffersToNativeWindow();
-
// Returns true iff all buffers on the given port have status
// OWNED_BY_US or OWNED_BY_NATIVE_WINDOW.
bool allYourBuffersAreBelongToUs(OMX_U32 portIndex);
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index f5d523d..56d2523 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -224,6 +224,7 @@
kFlagGatherCodecSpecificData = 512,
kFlagIsAsync = 1024,
kFlagIsComponentAllocated = 2048,
+ kFlagPushBlankBuffersOnShutdown = 4096,
};
struct BufferInfo {
diff --git a/include/media/stagefright/MediaCodecList.h b/include/media/stagefright/MediaCodecList.h
index 9d1d675..ce34338 100644
--- a/include/media/stagefright/MediaCodecList.h
+++ b/include/media/stagefright/MediaCodecList.h
@@ -54,7 +54,7 @@
static sp<IMediaCodecList> getLocalInstance();
// only to be used in getLocalInstance
- void updateDetailsForMultipleCodecs(const KeyedVector<AString, CodecSettings>& updates);
+ void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
private:
class BinderDeathObserver : public IBinder::DeathRecipient {
@@ -97,7 +97,6 @@
status_t initCheck() const;
void parseXMLFile(const char *path);
- void parseTopLevelXMLFile(const char *path, bool ignore_errors = false);
static void StartElementHandlerWrapper(
void *me, const char *name, const char **attrs);
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 84b1b1a..7fabcb3 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -298,7 +298,6 @@
status_t queueBufferToNativeWindow(BufferInfo *info);
status_t cancelBufferToNativeWindow(BufferInfo *info);
BufferInfo* dequeueBufferFromNativeWindow();
- status_t pushBlankBuffersToNativeWindow();
status_t freeBuffersOnPort(
OMX_U32 portIndex, bool onlyThoseWeOwn = false);
@@ -347,7 +346,6 @@
status_t configureCodec(const sp<MetaData> &meta);
- status_t applyRotation();
status_t waitForBufferFilled_l();
int64_t getDecodingTimeUs();
diff --git a/include/media/stagefright/SurfaceUtils.h b/include/media/stagefright/SurfaceUtils.h
new file mode 100644
index 0000000..c1a9c0a
--- /dev/null
+++ b/include/media/stagefright/SurfaceUtils.h
@@ -0,0 +1,34 @@
+/*
+ * 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 SURFACE_UTILS_H_
+
+#define SURFACE_UTILS_H_
+
+#include <utils/Errors.h>
+
+struct ANativeWindow;
+
+namespace android {
+
+status_t setNativeWindowSizeFormatAndUsage(
+ ANativeWindow *nativeWindow /* nonnull */,
+ int width, int height, int format, int rotation, int usage);
+status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */);
+
+} // namespace android
+
+#endif // SURFACE_UTILS_H_
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 23015c0..3868f13 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -85,6 +85,8 @@
int sessionId,
transfer_type transferType,
audio_input_flags_t flags,
+ int uid,
+ pid_t pid,
const audio_attributes_t* pAttributes)
: mStatus(NO_INIT),
mOpPackageName(opPackageName),
@@ -96,7 +98,7 @@
{
mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
- pAttributes);
+ uid, pid, pAttributes);
}
AudioRecord::~AudioRecord()
@@ -112,6 +114,10 @@
mAudioRecordThread->requestExitAndWait();
mAudioRecordThread.clear();
}
+ // No lock here: worst case we remove a NULL callback which will be a nop
+ if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ }
IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
mAudioRecord.clear();
mCblkMemory.clear();
@@ -136,12 +142,15 @@
int sessionId,
transfer_type transferType,
audio_input_flags_t flags,
+ int uid,
+ pid_t pid,
const audio_attributes_t* pAttributes)
{
ALOGV("set(): inputSource %d, sampleRate %u, format %#x, channelMask %#x, frameCount %zu, "
- "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s",
+ "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s "
+ "uid %d, pid %d",
inputSource, sampleRate, format, channelMask, frameCount, notificationFrames,
- sessionId, transferType, flags, String8(mOpPackageName).string());
+ sessionId, transferType, flags, String8(mOpPackageName).string(), uid, pid);
switch (transferType) {
case TRANSFER_DEFAULT:
@@ -228,6 +237,19 @@
}
ALOGV("set(): mSessionId %d", mSessionId);
+ int callingpid = IPCThreadState::self()->getCallingPid();
+ int mypid = getpid();
+ if (uid == -1 || (callingpid != mypid)) {
+ mClientUid = IPCThreadState::self()->getCallingUid();
+ } else {
+ mClientUid = uid;
+ }
+ if (pid == -1 || (callingpid != mypid)) {
+ mClientPid = callingpid;
+ } else {
+ mClientPid = pid;
+ }
+
mFlags = flags;
mCbf = cbf;
@@ -286,6 +308,8 @@
mNewPosition = mProxy->getPosition() + mUpdatePeriod;
int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
+ mActive = true;
+
status_t status = NO_ERROR;
if (!(flags & CBLK_INVALID)) {
status = mAudioRecord->start(event, triggerSession);
@@ -298,9 +322,9 @@
}
if (status != NO_ERROR) {
+ mActive = false;
ALOGE("start() status %d", status);
} else {
- mActive = true;
sp<AudioRecordThread> t = mAudioRecordThread;
if (t != 0) {
t->resume();
@@ -425,6 +449,11 @@
AutoMutex lock(mLock);
if (mSelectedDeviceId != deviceId) {
mSelectedDeviceId = deviceId;
+ // stop capture so that audio policy manager does not reject the new instance start request
+ // as only one capture can be active at a time.
+ if (mAudioRecord != 0 && mActive) {
+ mAudioRecord->stop();
+ }
android_atomic_or(CBLK_INVALID, &mCblk->mFlags);
}
return NO_ERROR;
@@ -435,6 +464,14 @@
return mSelectedDeviceId;
}
+audio_port_handle_t AudioRecord::getRoutedDeviceId() {
+ AutoMutex lock(mLock);
+ if (mInput == AUDIO_IO_HANDLE_NONE) {
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ return AudioSystem::getDeviceIdForIo(mInput);
+}
+
// -------------------------------------------------------------------------
// must be called with mLock held
@@ -478,6 +515,10 @@
}
}
+ if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ }
+
audio_io_handle_t input;
status_t status = AudioSystem::getInputForAttr(&mAttributes, &input,
(audio_session_t)mSessionId,
@@ -513,6 +554,7 @@
&temp,
&trackFlags,
tid,
+ mClientUid,
&mSessionId,
¬ificationFrames,
iMem,
@@ -609,6 +651,10 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
+ if (mDeviceCallback != 0) {
+ AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
+ }
+
return NO_ERROR;
}
@@ -1054,6 +1100,48 @@
return result;
}
+status_t AudioRecord::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+ if (callback == 0) {
+ ALOGW("%s adding NULL callback!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ AutoMutex lock(mLock);
+ if (mDeviceCallback == callback) {
+ ALOGW("%s adding same callback!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ status_t status = NO_ERROR;
+ if (mInput != AUDIO_IO_HANDLE_NONE) {
+ if (mDeviceCallback != 0) {
+ ALOGW("%s callback already present!", __FUNCTION__);
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ }
+ status = AudioSystem::addAudioDeviceCallback(callback, mInput);
+ }
+ mDeviceCallback = callback;
+ return status;
+}
+
+status_t AudioRecord::removeAudioDeviceCallback(
+ const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+ if (callback == 0) {
+ ALOGW("%s removing NULL callback!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ AutoMutex lock(mLock);
+ if (mDeviceCallback != callback) {
+ ALOGW("%s removing different callback!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (mInput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+ }
+ mDeviceCallback = 0;
+ return NO_ERROR;
+}
+
// =========================================================================
void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 85ed2b1..4c2e77b 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -76,6 +76,25 @@
return af;
}
+const sp<AudioSystem::AudioFlingerClient> AudioSystem::getAudioFlingerClient()
+{
+ // calling get_audio_flinger() will initialize gAudioFlingerClient if needed
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return 0;
+ Mutex::Autolock _l(gLock);
+ return gAudioFlingerClient;
+}
+
+sp<AudioIoDescriptor> AudioSystem::getIoDescriptor(audio_io_handle_t ioHandle)
+{
+ sp<AudioIoDescriptor> desc;
+ const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+ if (afc != 0) {
+ desc = afc->getIoDescriptor(ioHandle);
+ }
+ return desc;
+}
+
/* static */ status_t AudioSystem::checkAudioFlinger()
{
if (defaultServiceManager()->checkService(String16("media.audio_flinger")) != 0) {
@@ -249,9 +268,7 @@
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
-
- LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
- sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output);
+ sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output);
if (outputDesc == 0) {
ALOGV("getOutputSamplingRate() no output descriptor for output %d in gOutputs", output);
*samplingRate = af->sampleRate(output);
@@ -290,9 +307,7 @@
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
-
- LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
- sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output);
+ sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output);
if (outputDesc == 0) {
*frameCount = af->frameCount(output);
} else {
@@ -329,9 +344,7 @@
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
-
- LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
- sp<AudioIoDescriptor> outputDesc = gAudioFlingerClient->getIoDescriptor(output);
+ sp<AudioIoDescriptor> outputDesc = getIoDescriptor(output);
if (outputDesc == 0) {
*latency = af->latency(output);
} else {
@@ -346,10 +359,11 @@
status_t AudioSystem::getInputBufferSize(uint32_t sampleRate, audio_format_t format,
audio_channel_mask_t channelMask, size_t* buffSize)
{
- const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
- LOG_ALWAYS_FATAL_IF(gAudioFlingerClient == 0);
- return gAudioFlingerClient->getInputBufferSize(sampleRate, format, channelMask, buffSize);
+ const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+ if (afc == 0) {
+ return NO_INIT;
+ }
+ return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize);
}
status_t AudioSystem::setVoiceVolume(float value)
@@ -446,47 +460,77 @@
if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
- Mutex::Autolock _l(mLock);
+ audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
+ Vector < sp<AudioDeviceCallback> > callbacks;
- switch (event) {
- case AUDIO_OUTPUT_OPENED:
- case AUDIO_INPUT_OPENED: {
- if (getIoDescriptor(ioDesc->mIoHandle) != 0) {
- ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle);
- break;
- }
- mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
- ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
- "frameCount %zu", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
- ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
- ioDesc->mFrameCount);
- } break;
- case AUDIO_OUTPUT_CLOSED:
- case AUDIO_INPUT_CLOSED: {
- if (getIoDescriptor(ioDesc->mIoHandle) == 0) {
- ALOGW("ioConfigChanged() closing unknown %s %d",
+ {
+ Mutex::Autolock _l(mLock);
+
+ switch (event) {
+ case AUDIO_OUTPUT_OPENED:
+ case AUDIO_INPUT_OPENED: {
+ if (getIoDescriptor(ioDesc->mIoHandle) != 0) {
+ ALOGV("ioConfigChanged() opening already existing output! %d", ioDesc->mIoHandle);
+ break;
+ }
+ mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
+
+ if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
+ deviceId = ioDesc->getDeviceId();
+ ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+ if (ioIndex >= 0) {
+ callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ }
+ }
+ ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
+ "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
+ ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
+ ioDesc->mFrameCount, ioDesc->getDeviceId());
+ } break;
+ case AUDIO_OUTPUT_CLOSED:
+ case AUDIO_INPUT_CLOSED: {
+ if (getIoDescriptor(ioDesc->mIoHandle) == 0) {
+ ALOGW("ioConfigChanged() closing unknown %s %d",
+ event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle);
+ break;
+ }
+ ALOGV("ioConfigChanged() %s %d closed",
event == AUDIO_OUTPUT_CLOSED ? "output" : "input", ioDesc->mIoHandle);
- break;
- }
- ALOGV("ioConfigChanged() %s %d closed", event == AUDIO_OUTPUT_CLOSED ? "output" : "input",
- ioDesc->mIoHandle);
- mIoDescriptors.removeItem(ioDesc->mIoHandle);
+ mIoDescriptors.removeItem(ioDesc->mIoHandle);
+ mAudioDeviceCallbacks.removeItem(ioDesc->mIoHandle);
+ } break;
+
+ case AUDIO_OUTPUT_CONFIG_CHANGED:
+ case AUDIO_INPUT_CONFIG_CHANGED: {
+ sp<AudioIoDescriptor> oldDesc = getIoDescriptor(ioDesc->mIoHandle);
+ if (oldDesc == 0) {
+ ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle);
+ break;
+ }
+
+ deviceId = oldDesc->getDeviceId();
+ mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
+
+ if (deviceId != ioDesc->getDeviceId()) {
+ deviceId = ioDesc->getDeviceId();
+ ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+ if (ioIndex >= 0) {
+ callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ }
+ }
+ ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x "
+ "channel mask %#x frameCount %zu deviceId %d",
+ event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input",
+ ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat,
+ ioDesc->mChannelMask, ioDesc->mFrameCount, ioDesc->getDeviceId());
+
} break;
-
- case AUDIO_OUTPUT_CONFIG_CHANGED:
- case AUDIO_INPUT_CONFIG_CHANGED: {
- if (getIoDescriptor(ioDesc->mIoHandle) == 0) {
- ALOGW("ioConfigChanged() modifying unknown output! %d", ioDesc->mIoHandle);
- break;
}
- mIoDescriptors.replaceValueFor(ioDesc->mIoHandle, ioDesc);
- ALOGV("ioConfigChanged() new config for %s %d samplingRate %u, format %#x "
- "channel mask %#x frameCount %zu",
- event == AUDIO_OUTPUT_CONFIG_CHANGED ? "output" : "input",
- ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat,
- ioDesc->mChannelMask, ioDesc->mFrameCount);
- } break;
+ }
+ // callbacks.size() != 0 => ioDesc->mIoHandle and deviceId are valid
+ for (size_t i = 0; i < callbacks.size(); i++) {
+ callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
}
}
@@ -532,7 +576,56 @@
return desc;
}
-/*static*/ void AudioSystem::setErrorCallback(audio_error_callback cb)
+status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
+ const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+ Mutex::Autolock _l(mLock);
+ Vector < sp<AudioDeviceCallback> > callbacks;
+ ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+ if (ioIndex >= 0) {
+ callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+ }
+
+ for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
+ if (callbacks[cbIndex] == callback) {
+ return INVALID_OPERATION;
+ }
+ }
+ callbacks.add(callback);
+
+ mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+ return NO_ERROR;
+}
+
+status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
+ const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+ Mutex::Autolock _l(mLock);
+ ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
+ if (ioIndex < 0) {
+ return INVALID_OPERATION;
+ }
+ Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+
+ size_t cbIndex;
+ for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
+ if (callbacks[cbIndex] == callback) {
+ break;
+ }
+ }
+ if (cbIndex == callbacks.size()) {
+ return INVALID_OPERATION;
+ }
+ callbacks.removeAt(cbIndex);
+ if (callbacks.size() != 0) {
+ mAudioDeviceCallbacks.replaceValueFor(audioIo, callbacks);
+ } else {
+ mAudioDeviceCallbacks.removeItem(audioIo);
+ }
+ return NO_ERROR;
+}
+
+/* static */ void AudioSystem::setErrorCallback(audio_error_callback cb)
{
Mutex::Autolock _l(gLock);
gAudioErrorCallback = cb;
@@ -864,11 +957,11 @@
{
// called by restoreTrack_l(), which needs new IAudioFlinger and IAudioPolicyService instances
ALOGV("clearAudioConfigCache()");
- if (gAudioFlingerClient != 0) {
- gAudioFlingerClient->clearIoCache();
- }
{
Mutex::Autolock _l(gLock);
+ if (gAudioFlingerClient != 0) {
+ gAudioFlingerClient->clearIoCache();
+ }
gAudioFlinger.clear();
}
{
@@ -934,7 +1027,7 @@
return aps->setAudioPortConfig(config);
}
-status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callBack)
+status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callback)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
@@ -943,11 +1036,11 @@
if (gAudioPolicyServiceClient == 0) {
return NO_INIT;
}
- return gAudioPolicyServiceClient->addAudioPortCallback(callBack);
+ return gAudioPolicyServiceClient->addAudioPortCallback(callback);
}
/*static*/
-status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callBack)
+status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callback)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
@@ -956,7 +1049,38 @@
if (gAudioPolicyServiceClient == 0) {
return NO_INIT;
}
- return gAudioPolicyServiceClient->removeAudioPortCallback(callBack);
+ return gAudioPolicyServiceClient->removeAudioPortCallback(callback);
+}
+
+status_t AudioSystem::addAudioDeviceCallback(
+ const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+ const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+ if (afc == 0) {
+ return NO_INIT;
+ }
+ return afc->addAudioDeviceCallback(callback, audioIo);
+}
+
+status_t AudioSystem::removeAudioDeviceCallback(
+ const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+{
+ const sp<AudioFlingerClient> afc = getAudioFlingerClient();
+ if (afc == 0) {
+ return NO_INIT;
+ }
+ return afc->removeAudioDeviceCallback(callback, audioIo);
+}
+
+audio_port_handle_t AudioSystem::getDeviceIdForIo(audio_io_handle_t audioIo)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ const sp<AudioIoDescriptor> desc = getIoDescriptor(audioIo);
+ if (desc == 0) {
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ return desc->getDeviceId();
}
status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session,
@@ -1008,25 +1132,25 @@
// ---------------------------------------------------------------------------
status_t AudioSystem::AudioPolicyServiceClient::addAudioPortCallback(
- const sp<AudioPortCallback>& callBack)
+ const sp<AudioPortCallback>& callback)
{
Mutex::Autolock _l(mLock);
for (size_t i = 0; i < mAudioPortCallbacks.size(); i++) {
- if (mAudioPortCallbacks[i] == callBack) {
+ if (mAudioPortCallbacks[i] == callback) {
return INVALID_OPERATION;
}
}
- mAudioPortCallbacks.add(callBack);
+ mAudioPortCallbacks.add(callback);
return NO_ERROR;
}
status_t AudioSystem::AudioPolicyServiceClient::removeAudioPortCallback(
- const sp<AudioPortCallback>& callBack)
+ const sp<AudioPortCallback>& callback)
{
Mutex::Autolock _l(mLock);
size_t i;
for (i = 0; i < mAudioPortCallbacks.size(); i++) {
- if (mAudioPortCallbacks[i] == callBack) {
+ if (mAudioPortCallbacks[i] == callback) {
break;
}
}
@@ -1037,6 +1161,7 @@
return NO_ERROR;
}
+
void AudioSystem::AudioPolicyServiceClient::onAudioPortListUpdate()
{
Mutex::Autolock _l(mLock);
diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp
index bb47d3e..db316b0 100644
--- a/media/libmedia/AudioTrack.cpp
+++ b/media/libmedia/AudioTrack.cpp
@@ -234,6 +234,10 @@
mAudioTrackThread->requestExitAndWait();
mAudioTrackThread.clear();
}
+ // No lock here: worst case we remove a NULL callback which will be a nop
+ if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+ }
IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
mAudioTrack.clear();
mCblkMemory.clear();
@@ -1042,6 +1046,14 @@
return mSelectedDeviceId;
}
+audio_port_handle_t AudioTrack::getRoutedDeviceId() {
+ AutoMutex lock(mLock);
+ if (mOutput == AUDIO_IO_HANDLE_NONE) {
+ return AUDIO_PORT_HANDLE_NONE;
+ }
+ return AudioSystem::getDeviceIdForIo(mOutput);
+}
+
status_t AudioTrack::attachAuxEffect(int effectId)
{
AutoMutex lock(mLock);
@@ -1071,6 +1083,9 @@
return NO_INIT;
}
+ if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+ }
audio_io_handle_t output;
audio_stream_type_t streamType = mStreamType;
audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
@@ -1375,6 +1390,10 @@
mDeathNotifier = new DeathNotifier(this);
IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
+ if (mDeviceCallback != 0) {
+ AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput);
+ }
+
return NO_ERROR;
}
@@ -2308,6 +2327,48 @@
return mProxy->getUnderrunFrames();
}
+status_t AudioTrack::addAudioDeviceCallback(const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+ if (callback == 0) {
+ ALOGW("%s adding NULL callback!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ AutoMutex lock(mLock);
+ if (mDeviceCallback == callback) {
+ ALOGW("%s adding same callback!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ status_t status = NO_ERROR;
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
+ if (mDeviceCallback != 0) {
+ ALOGW("%s callback already present!", __FUNCTION__);
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+ }
+ status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
+ }
+ mDeviceCallback = callback;
+ return status;
+}
+
+status_t AudioTrack::removeAudioDeviceCallback(
+ const sp<AudioSystem::AudioDeviceCallback>& callback)
+{
+ if (callback == 0) {
+ ALOGW("%s removing NULL callback!", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ AutoMutex lock(mLock);
+ if (mDeviceCallback != callback) {
+ ALOGW("%s removing different callback!", __FUNCTION__);
+ return INVALID_OPERATION;
+ }
+ if (mOutput != AUDIO_IO_HANDLE_NONE) {
+ AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+ }
+ mDeviceCallback = 0;
+ return NO_ERROR;
+}
+
// =========================================================================
void AudioTrack::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp
index d48532e..d722fe9 100644
--- a/media/libmedia/IAudioFlinger.cpp
+++ b/media/libmedia/IAudioFlinger.cpp
@@ -178,6 +178,7 @@
size_t *pFrameCount,
track_flags_t *flags,
pid_t tid,
+ int clientUid,
int *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
@@ -197,6 +198,7 @@
track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT;
data.writeInt32(lFlags);
data.writeInt32((int32_t) tid);
+ data.writeInt32((int32_t) clientUid);
int lSessionId = AUDIO_SESSION_ALLOCATE;
if (sessionId != NULL) {
lSessionId = *sessionId;
@@ -958,6 +960,7 @@
size_t frameCount = data.readInt64();
track_flags_t flags = (track_flags_t) data.readInt32();
pid_t tid = (pid_t) data.readInt32();
+ int clientUid = data.readInt32();
int sessionId = data.readInt32();
size_t notificationFrames = data.readInt64();
sp<IMemory> cblk;
@@ -965,7 +968,7 @@
status_t status;
sp<IAudioRecord> record = openRecord(input,
sampleRate, format, channelMask, opPackageName, &frameCount, &flags, tid,
- &sessionId, ¬ificationFrames, cblk, buffers, &status);
+ clientUid, &sessionId, ¬ificationFrames, cblk, buffers, &status);
LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR));
reply->writeInt64(frameCount);
reply->writeInt32(flags);
diff --git a/media/libmedia/IAudioFlingerClient.cpp b/media/libmedia/IAudioFlingerClient.cpp
index a622241..3429d36 100644
--- a/media/libmedia/IAudioFlingerClient.cpp
+++ b/media/libmedia/IAudioFlingerClient.cpp
@@ -45,6 +45,7 @@
data.writeInterfaceToken(IAudioFlingerClient::getInterfaceDescriptor());
data.writeInt32(event);
data.writeInt32((int32_t)ioDesc->mIoHandle);
+ data.write(&ioDesc->mPatch, sizeof(struct audio_patch));
data.writeInt32(ioDesc->mSamplingRate);
data.writeInt32(ioDesc->mFormat);
data.writeInt32(ioDesc->mChannelMask);
@@ -67,6 +68,7 @@
audio_io_config_event event = (audio_io_config_event)data.readInt32();
sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
ioDesc->mIoHandle = (audio_io_handle_t) data.readInt32();
+ data.read(&ioDesc->mPatch, sizeof(struct audio_patch));
ioDesc->mSamplingRate = data.readInt32();
ioDesc->mFormat = (audio_format_t) data.readInt32();
ioDesc->mChannelMask = (audio_channel_mask_t) data.readInt32();
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 9246a7c..2f440fe 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -142,7 +142,7 @@
ssize_t result = reply.readInt32();
- if (result >= ERROR_DRM_VENDOR_MIN && result <= ERROR_DRM_VENDOR_MAX) {
+ if (isCryptoError(result)) {
errorDetailMsg->setTo(reply.readCString());
}
@@ -319,8 +319,7 @@
reply->writeInt32(result);
- if (result >= ERROR_DRM_VENDOR_MIN
- && result <= ERROR_DRM_VENDOR_MAX) {
+ if (isCryptoError(result)) {
reply->writeCString(errorDetailMsg.c_str());
}
diff --git a/media/libmedia/IMediaHTTPConnection.cpp b/media/libmedia/IMediaHTTPConnection.cpp
index 2ff7658..09137ef 100644
--- a/media/libmedia/IMediaHTTPConnection.cpp
+++ b/media/libmedia/IMediaHTTPConnection.cpp
@@ -24,6 +24,7 @@
#include <binder/Parcel.h>
#include <utils/String8.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/MediaErrors.h>
namespace android {
@@ -106,11 +107,18 @@
return UNKNOWN_ERROR;
}
- int32_t len = reply.readInt32();
+ size_t len = reply.readInt32();
- if (len > 0) {
- memcpy(buffer, mMemory->pointer(), len);
+ if (len > size) {
+ ALOGE("requested %zu, got %zu", size, len);
+ return ERROR_OUT_OF_RANGE;
}
+ if (len > mMemory->size()) {
+ ALOGE("got %zu, but memory has %zu", len, mMemory->size());
+ return ERROR_OUT_OF_RANGE;
+ }
+
+ memcpy(buffer, mMemory->pointer(), len);
return len;
}
diff --git a/media/libmedia/IMediaHTTPService.cpp b/media/libmedia/IMediaHTTPService.cpp
index f30d0f3..0c16a2b 100644
--- a/media/libmedia/IMediaHTTPService.cpp
+++ b/media/libmedia/IMediaHTTPService.cpp
@@ -44,6 +44,7 @@
status_t err = reply.readInt32();
if (err != OK) {
+ ALOGE("Unable to make HTTP connection (err = %d)", err);
return NULL;
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 9963353..1fb4365 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -189,7 +189,8 @@
mVideoFpsHint(-1.f),
mStarted(false),
mPaused(false),
- mPausedByClient(false) {
+ mPausedByClient(false),
+ mPausedForBuffering(false) {
clearFlushComplete();
}
@@ -423,7 +424,19 @@
CHECK(format->findInt32("type", &trackType));
AString mime;
- CHECK(format->findString("mime", &mime));
+ if (!format->findString("mime", &mime)) {
+ // Java MediaPlayer only uses mimetype for subtitle and timedtext tracks.
+ // If we can't find the mimetype here it means that we wouldn't be needing
+ // the mimetype on the Java end. We still write a placeholder mime to keep the
+ // (de)serialization logic simple.
+ if (trackType == MEDIA_TRACK_TYPE_AUDIO) {
+ mime = "audio/";
+ } else if (trackType == MEDIA_TRACK_TYPE_VIDEO) {
+ mime = "video/";
+ } else {
+ TRESPASS();
+ }
+ }
AString lang;
CHECK(format->findString("language", &lang));
@@ -671,7 +684,10 @@
{
ALOGV("kWhatStart");
if (mStarted) {
- onResume();
+ // do not resume yet if the source is still buffering
+ if (!mPausedForBuffering) {
+ onResume();
+ }
} else {
onStart();
}
@@ -704,9 +720,8 @@
}
if (mVideoDecoder != NULL) {
- sp<MetaData> meta = getFileMeta();
- int32_t rate;
- if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
+ float rate = getFrameRate();
+ if (rate > 0) {
sp<AMessage> params = new AMessage();
params->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
mVideoDecoder->setParameters(params);
@@ -1265,10 +1280,8 @@
return;
}
- sp<MetaData> meta = getFileMeta();
- int32_t rate;
- if (meta != NULL
- && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
+ float rate = getFrameRate();
+ if (rate > 0) {
mRenderer->setVideoFrameRate(rate);
}
@@ -1426,9 +1439,8 @@
format->setInt32("protected", true);
}
- sp<MetaData> meta = getFileMeta();
- int32_t rate;
- if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) {
+ float rate = getFrameRate();
+ if (rate > 0) {
format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed);
}
}
@@ -1702,6 +1714,28 @@
return mSource->getFileFormatMeta();
}
+float NuPlayer::getFrameRate() {
+ sp<MetaData> meta = mSource->getFormatMeta(false /* audio */);
+ if (meta == NULL) {
+ return 0;
+ }
+ int32_t rate;
+ if (!meta->findInt32(kKeyFrameRate, &rate)) {
+ // fall back to try file meta
+ sp<MetaData> fileMeta = getFileMeta();
+ if (fileMeta == NULL) {
+ ALOGW("source has video meta but not file meta");
+ return -1;
+ }
+ int32_t fileMetaRate;
+ if (!fileMeta->findInt32(kKeyFrameRate, &fileMetaRate)) {
+ return -1;
+ }
+ return fileMetaRate;
+ }
+ return rate;
+}
+
void NuPlayer::schedulePollDuration() {
sp<AMessage> msg = new AMessage(kWhatPollDuration, this);
msg->setInt32("generation", mPollDurationGeneration);
@@ -1977,9 +2011,10 @@
case Source::kWhatPauseOnBufferingStart:
{
// ignore if not playing
- if (mStarted && !mPausedByClient) {
+ if (mStarted) {
ALOGI("buffer low, pausing...");
+ mPausedForBuffering = true;
onPause();
}
// fall-thru
@@ -1994,10 +2029,15 @@
case Source::kWhatResumeOnBufferingEnd:
{
// ignore if not playing
- if (mStarted && !mPausedByClient) {
+ if (mStarted) {
ALOGI("buffer ready, resuming...");
- onResume();
+ mPausedForBuffering = false;
+
+ // do not resume yet if client didn't unpause
+ if (!mPausedByClient) {
+ onResume();
+ }
}
// fall-thru
}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index fcf6841..df9debc 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -80,6 +80,7 @@
void getStats(int64_t *mNumFramesTotal, int64_t *mNumFramesDropped);
sp<MetaData> getFileMeta();
+ float getFrameRate();
protected:
virtual ~NuPlayer();
@@ -202,6 +203,9 @@
// still become true, when we pause internally due to buffering.
bool mPausedByClient;
+ // Pause state as requested by source (internally) due to buffering
+ bool mPausedForBuffering;
+
inline const sp<DecoderBase> &getDecoder(bool audio) {
return audio ? mAudioDecoder : mVideoDecoder;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b7798d2..5475a4a 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -42,6 +42,7 @@
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/SurfaceUtils.h>
#include <media/hardware/HardwareAPI.h>
#include <OMX_AudioExt.h>
@@ -650,6 +651,11 @@
(void)surface->getIGraphicBufferProducer()->allowAllocation(false);
}
+ // push blank buffers to previous window if requested
+ if (mFlags & kFlagPushBlankBuffersToNativeWindowOnShutdown) {
+ pushBlankBuffersToNativeWindow(mNativeWindow.get());
+ }
+
mNativeWindow = nativeWindow;
return OK;
}
@@ -748,82 +754,6 @@
return OK;
}
-status_t ACodec::setNativeWindowSizeFormatAndUsage(
- ANativeWindow *nativeWindow /* nonnull */,
- int width, int height, int format, int rotation, int usage) {
- status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height);
- if (err != 0) {
- ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_buffers_format(nativeWindow, format);
- if (err != 0) {
- ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- int transform = 0;
- if ((rotation % 90) == 0) {
- switch ((rotation / 90) & 3) {
- case 1: transform = HAL_TRANSFORM_ROT_90; break;
- case 2: transform = HAL_TRANSFORM_ROT_180; break;
- case 3: transform = HAL_TRANSFORM_ROT_270; break;
- default: transform = 0; break;
- }
- }
-
- err = native_window_set_buffers_transform(nativeWindow, transform);
- if (err != 0) {
- ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- // Make sure to check whether either Stagefright or the video decoder
- // requested protected buffers.
- if (usage & GRALLOC_USAGE_PROTECTED) {
- // Verify that the ANativeWindow sends images directly to
- // SurfaceFlinger.
- int queuesToNativeWindow = 0;
- err = nativeWindow->query(
- nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow);
- if (err != 0) {
- ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err);
- return err;
- }
- if (queuesToNativeWindow != 1) {
- ALOGE("native window could not be authenticated");
- return PERMISSION_DENIED;
- }
- }
-
- int consumerUsage = 0;
- err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
- if (err != 0) {
- ALOGW("failed to get consumer usage bits. ignoring");
- err = 0;
- }
-
- int finalUsage = usage | consumerUsage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP;
- ALOGV("gralloc usage: %#x(ACodec) + %#x(Consumer) = %#x", usage, consumerUsage, finalUsage);
- err = native_window_set_usage(nativeWindow, finalUsage);
- if (err != 0) {
- ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_scaling_mode(
- nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- if (err != 0) {
- ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err);
- return err;
- }
-
- ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x",
- nativeWindow, width, height, format, rotation, finalUsage);
- return OK;
-}
-
status_t ACodec::setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */) {
OMX_PARAM_PORTDEFINITIONTYPE def;
InitOMXParams(&def);
@@ -849,6 +779,8 @@
usage |= GRALLOC_USAGE_PROTECTED;
}
+ usage |= GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP;
+
ALOGV("gralloc usage: %#x(OMX) => %#x(ACodec)", omxUsage, usage);
return setNativeWindowSizeFormatAndUsage(
nativeWindow,
@@ -4123,134 +4055,6 @@
notify->post();
}
-status_t ACodec::pushBlankBuffersToNativeWindow() {
- status_t err = NO_ERROR;
- ANativeWindowBuffer* anb = NULL;
- int numBufs = 0;
- int minUndequeuedBufs = 0;
-
- // We need to reconnect to the ANativeWindow as a CPU client to ensure that
- // no frames get dropped by SurfaceFlinger assuming that these are video
- // frames.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = setNativeWindowSizeFormatAndUsage(
- mNativeWindow.get(), 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set format failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = mNativeWindow->query(mNativeWindow.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
- "failed: %s (%d)", strerror(-err), -err);
- goto error;
- }
-
- numBufs = minUndequeuedBufs + 1;
- err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- // We push numBufs + 1 buffers to ensure that we've drawn into the same
- // buffer twice. This should guarantee that the buffer has been displayed
- // on the screen and then been replaced, so an previous video frames are
- // guaranteed NOT to be currently displayed.
- for (int i = 0; i < numBufs + 1; i++) {
- err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-
- // Fill the buffer with the a 1x1 checkerboard pattern ;)
- uint32_t* img = NULL;
- err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: lock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- *img = 0;
-
- err = buf->unlock();
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: unlock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = mNativeWindow->queueBuffer(mNativeWindow.get(),
- buf->getNativeBuffer(), -1);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- anb = NULL;
- }
-
-error:
-
- if (err != NO_ERROR) {
- // Clean up after an error.
- if (anb != NULL) {
- mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
- }
-
- native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
-
- return err;
- } else {
- // Clean up after success.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- return NO_ERROR;
- }
-}
-
////////////////////////////////////////////////////////////////////////////////
ACodec::PortDescription::PortDescription() {
@@ -6145,7 +5949,7 @@
// them has made it to the display. This allows the OMX
// component teardown to zero out any protected buffers
// without the risk of scanning out one of those buffers.
- mCodec->pushBlankBuffersToNativeWindow();
+ pushBlankBuffersToNativeWindow(mCodec->mNativeWindow.get());
}
mCodec->changeState(mCodec->mIdleToLoadedState);
diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk
index 45581f3..fa17b2e 100644
--- a/media/libstagefright/Android.mk
+++ b/media/libstagefright/Android.mk
@@ -57,6 +57,7 @@
StagefrightMediaScanner.cpp \
StagefrightMetadataRetriever.cpp \
SurfaceMediaSource.cpp \
+ SurfaceUtils.cpp \
ThrottledSource.cpp \
TimeSource.cpp \
TimedEventQueue.cpp \
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 6573afc..1f1d751 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2605,11 +2605,11 @@
}
status_t MPEG4Extractor::parse3GPPMetaData(off64_t offset, size_t size, int depth) {
- if (size < 4) {
+ if (size < 4 || size == SIZE_MAX) {
return ERROR_MALFORMED;
}
- uint8_t *buffer = new (std::nothrow) uint8_t[size];
+ uint8_t *buffer = new (std::nothrow) uint8_t[size + 1];
if (buffer == NULL) {
return ERROR_MALFORMED;
}
@@ -2701,6 +2701,7 @@
}
if (isUTF8) {
+ buffer[size] = 0;
mFileMetaData->setCString(metadataKey, (const char *)buffer + 6);
} else {
// Convert from UTF-16 string to UTF-8 string.
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index beb12ec..3bc22f2 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -94,6 +94,7 @@
void addChunkOffset(off64_t offset);
int32_t getTrackId() const { return mTrackId; }
status_t dump(int fd, const Vector<String16>& args) const;
+ static const char *getFourCCForMime(const char *mime);
private:
enum {
@@ -426,6 +427,33 @@
return OK;
}
+// static
+const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) {
+ if (mime == NULL) {
+ return NULL;
+ }
+ if (!strncasecmp(mime, "audio/", 6)) {
+ if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
+ return "samr";
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
+ return "sawb";
+ } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
+ return "mp4a";
+ }
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
+ return "mp4v";
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
+ return "s263";
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
+ return "avc1";
+ }
+ } else {
+ ALOGE("Track (%s) other than video or audio is not supported", mime);
+ }
+ return NULL;
+}
+
status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
Mutex::Autolock l(mLock);
if (mStarted) {
@@ -441,14 +469,11 @@
CHECK(source.get() != NULL);
- // A track of type other than video or audio is not supported.
const char *mime;
source->getFormat()->findCString(kKeyMIMEType, &mime);
bool isAudio = !strncasecmp(mime, "audio/", 6);
- bool isVideo = !strncasecmp(mime, "video/", 6);
- if (!isAudio && !isVideo) {
- ALOGE("Track (%s) other than video or audio is not supported",
- mime);
+ if (Track::getFourCCForMime(mime) == NULL) {
+ ALOGE("Unsupported mime '%s'", mime);
return ERROR_UNSUPPORTED;
}
@@ -2730,17 +2755,13 @@
const char *mime;
bool success = mMeta->findCString(kKeyMIMEType, &mime);
CHECK(success);
- if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
- mOwner->beginBox("mp4v");
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
- mOwner->beginBox("s263");
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
- mOwner->beginBox("avc1");
- } else {
+ const char *fourcc = getFourCCForMime(mime);
+ if (fourcc == NULL) {
ALOGE("Unknown mime type '%s'.", mime);
CHECK(!"should not be here, unknown mime type.");
}
+ mOwner->beginBox(fourcc); // video format
mOwner->writeInt32(0); // reserved
mOwner->writeInt16(0); // reserved
mOwner->writeInt16(1); // data ref index
@@ -2784,14 +2805,8 @@
const char *mime;
bool success = mMeta->findCString(kKeyMIMEType, &mime);
CHECK(success);
- const char *fourcc = NULL;
- if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_NB, mime)) {
- fourcc = "samr";
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime)) {
- fourcc = "sawb";
- } else if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime)) {
- fourcc = "mp4a";
- } else {
+ const char *fourcc = getFourCCForMime(mime);
+ if (fourcc == NULL) {
ALOGE("Unknown mime type '%s'.", mime);
CHECK(!"should not be here, unknown mime type.");
}
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ed4f682..44f6542 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -46,6 +46,7 @@
#include <media/stagefright/OMXClient.h>
#include <media/stagefright/OMXCodec.h>
#include <media/stagefright/PersistentSurface.h>
+#include <media/stagefright/SurfaceUtils.h>
#include <private/android_filesystem_config.h>
#include <utils/Log.h>
#include <utils/Singleton.h>
@@ -1659,6 +1660,11 @@
sp<AMessage> format;
CHECK(msg->findMessage("format", &format));
+ int32_t push;
+ if (msg->findInt32("push-blank-buffers-on-shutdown", &push) && push != 0) {
+ mFlags |= kFlagPushBlankBuffersOnShutdown;
+ }
+
if (obj != NULL) {
format->setObject("native-window", obj);
status_t err = handleSetSurface(static_cast<Surface *>(obj.get()));
@@ -1725,6 +1731,10 @@
} else {
if (err == OK) {
if (mFlags & kFlagUsesSoftwareRenderer) {
+ if (mSoftRenderer != NULL
+ && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
+ pushBlankBuffersToNativeWindow(mSurface.get());
+ }
mSoftRenderer = new SoftwareRenderer(surface);
// TODO: check if this was successful
} else {
@@ -1848,6 +1858,10 @@
msg->what() == kWhatStop /* keepComponentAllocated */);
returnBuffersToCodec();
+
+ if (mSoftRenderer != NULL && (mFlags & kFlagPushBlankBuffersOnShutdown)) {
+ pushBlankBuffersToNativeWindow(mSurface.get());
+ }
break;
}
diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp
index f12a913..e212fb8 100644
--- a/media/libstagefright/MediaCodecList.cpp
+++ b/media/libstagefright/MediaCodecList.cpp
@@ -44,8 +44,6 @@
static MediaCodecList *gCodecList = NULL;
-static const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
-
static bool parseBoolean(const char *s) {
if (!strcasecmp(s, "true") || !strcasecmp(s, "yes") || !strcasecmp(s, "y")) {
return true;
@@ -61,7 +59,6 @@
// static
sp<IMediaCodecList> MediaCodecList::getLocalInstance() {
bool profilingNeeded = false;
- KeyedVector<AString, CodecSettings> updates;
Vector<sp<MediaCodecInfo>> infos;
{
@@ -89,13 +86,13 @@
}
if (profilingNeeded) {
- profileCodecs(infos, &updates);
+ profileCodecs(infos);
}
{
Mutex::Autolock autoLock(sInitMutex);
- if (updates.size() > 0) {
- gCodecList->updateDetailsForMultipleCodecs(updates);
+ if (profilingNeeded) {
+ gCodecList->parseTopLevelXMLFile(kProfilingResults, true /* ignore_errors */);
}
return sCodecList;
@@ -145,19 +142,6 @@
parseTopLevelXMLFile(kProfilingResults, true/* ignore_errors */);
}
-void MediaCodecList::updateDetailsForMultipleCodecs(
- const KeyedVector<AString, CodecSettings>& updates) {
- if (updates.size() == 0) {
- return;
- }
-
- exportResultsToXML(kProfilingResults, updates);
-
- for (size_t i = 0; i < updates.size(); ++i) {
- applyCodecSettings(updates.keyAt(i), updates.valueAt(i), &mCodecInfos);
- }
-}
-
void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_errors) {
// get href_base
char *href_base_end = strrchr(codecs_xml, '/');
diff --git a/media/libstagefright/MediaCodecListOverrides.cpp b/media/libstagefright/MediaCodecListOverrides.cpp
index 265b1ea..535db09 100644
--- a/media/libstagefright/MediaCodecListOverrides.cpp
+++ b/media/libstagefright/MediaCodecListOverrides.cpp
@@ -30,6 +30,8 @@
namespace android {
+const char *kProfilingResults = "/data/misc/media/media_codecs_profiling_results.xml";
+
// a limit to avoid allocating unreasonable number of codec instances in the measurement.
// this should be in sync with the MAX_SUPPORTED_INSTANCES defined in MediaCodecInfo.java.
static const int kMaxInstances = 32;
@@ -171,20 +173,6 @@
return codecs.size();
}
-static void printLongString(const char *buf, size_t size) {
- AString print;
- const char *start = buf;
- size_t len;
- size_t totalLen = size;
- while (totalLen > 0) {
- len = (totalLen > 500) ? 500 : totalLen;
- print.setTo(start, len);
- ALOGV("%s", print.c_str());
- totalLen -= len;
- start += len;
- }
-}
-
bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2) {
ssize_t pos = s.find(delimiter.c_str());
if (pos < 0) {
@@ -207,9 +195,18 @@
return true;
}
+void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos) {
+ CodecSettings global_results; // TODO: add global results.
+ KeyedVector<AString, CodecSettings> encoder_results;
+ KeyedVector<AString, CodecSettings> decoder_results;
+ profileCodecs(infos, &encoder_results, &decoder_results);
+ exportResultsToXML(kProfilingResults, global_results, encoder_results, decoder_results);
+}
+
void profileCodecs(
const Vector<sp<MediaCodecInfo>> &infos,
- KeyedVector<AString, CodecSettings> *results,
+ KeyedVector<AString, CodecSettings> *encoder_results,
+ KeyedVector<AString, CodecSettings> *decoder_results,
bool forceToMeasure) {
KeyedVector<AString, sp<MediaCodecInfo::Capabilities>> codecsNeedMeasure;
for (size_t i = 0; i < infos.size(); ++i) {
@@ -240,157 +237,86 @@
AString key = name;
key.append(" ");
key.append(mimes[i]);
- key.append(" ");
- key.append(info->isEncoder() ? "encoder" : "decoder");
- results->add(key, settings);
+
+ if (info->isEncoder()) {
+ encoder_results->add(key, settings);
+ } else {
+ decoder_results->add(key, settings);
+ }
}
}
}
}
-void applyCodecSettings(
- const AString& codecInfo,
- const CodecSettings &settings,
- Vector<sp<MediaCodecInfo>> *infos) {
- AString name;
- AString mime;
- AString type;
- if (!splitString(codecInfo, " ", &name, &mime, &type)) {
- return;
- }
-
- for (size_t i = 0; i < infos->size(); ++i) {
- const sp<MediaCodecInfo> &info = infos->itemAt(i);
- if (name != info->getCodecName()) {
- continue;
- }
-
- Vector<AString> mimes;
- info->getSupportedMimes(&mimes);
- for (size_t j = 0; j < mimes.size(); ++j) {
- if (mimes[j] != mime) {
- continue;
- }
- const sp<MediaCodecInfo::Capabilities> &caps = info->getCapabilitiesFor(mime.c_str());
- for (size_t k = 0; k < settings.size(); ++k) {
- caps->getDetails()->setString(
- settings.keyAt(k).c_str(), settings.valueAt(k).c_str());
- }
- }
- }
-}
-
-void exportResultsToXML(const char *fileName, const KeyedVector<AString, CodecSettings>& results) {
-#if LOG_NDEBUG == 0
- ALOGE("measurement results");
+static AString globalResultsToXml(const CodecSettings& results) {
+ AString ret;
for (size_t i = 0; i < results.size(); ++i) {
- ALOGE("key %s", results.keyAt(i).c_str());
- const CodecSettings &settings = results.valueAt(i);
- for (size_t j = 0; j < settings.size(); ++j) {
- ALOGE("name %s value %s", settings.keyAt(j).c_str(), settings.valueAt(j).c_str());
- }
+ AString setting = AStringPrintf(
+ " <Setting name=\"%s\" value=\"%s\" />\n",
+ results.keyAt(i).c_str(),
+ results.valueAt(i).c_str());
+ ret.append(setting);
}
-#endif
+ return ret;
+}
- AString overrides;
- FILE *f = fopen(fileName, "rb");
- if (f != NULL) {
- fseek(f, 0, SEEK_END);
- long size = ftell(f);
- rewind(f);
-
- char *buf = (char *)malloc(size);
- if (fread(buf, size, 1, f) == 1) {
- overrides.setTo(buf, size);
- if (!LOG_NDEBUG) {
- ALOGV("Existing overrides:");
- printLongString(buf, size);
- }
- } else {
- ALOGE("Failed to read %s", fileName);
- }
- fclose(f);
- free(buf);
- }
-
+static AString codecResultsToXml(const KeyedVector<AString, CodecSettings>& results) {
+ AString ret;
for (size_t i = 0; i < results.size(); ++i) {
AString name;
AString mime;
- AString type;
- if (!splitString(results.keyAt(i), " ", &name, &mime, &type)) {
+ if (!splitString(results.keyAt(i), " ", &name, &mime)) {
continue;
}
- name = AStringPrintf("\"%s\"", name.c_str());
- mime = AStringPrintf("\"%s\"", mime.c_str());
- ALOGV("name(%s) mime(%s) type(%s)", name.c_str(), mime.c_str(), type.c_str());
- ssize_t posCodec = overrides.find(name.c_str());
- size_t posInsert = 0;
- if (posCodec < 0) {
- AString encodersDecoders = (type == "encoder") ? "<Encoders>" : "<Decoders>";
- AString encodersDecodersEnd = (type == "encoder") ? "</Encoders>" : "</Decoders>";
- ssize_t posEncodersDecoders = overrides.find(encodersDecoders.c_str());
- if (posEncodersDecoders < 0) {
- AString mediaCodecs = "<MediaCodecs>";
- ssize_t posMediaCodec = overrides.find(mediaCodecs.c_str());
- if (posMediaCodec < 0) {
- posMediaCodec = overrides.size();
- overrides.insert("\n<MediaCodecs>\n</MediaCodecs>\n", posMediaCodec);
- posMediaCodec = overrides.find(mediaCodecs.c_str(), posMediaCodec);
- }
- posEncodersDecoders = posMediaCodec + mediaCodecs.size();
- AString codecs = AStringPrintf(
- "\n %s\n %s", encodersDecoders.c_str(), encodersDecodersEnd.c_str());
- overrides.insert(codecs.c_str(), posEncodersDecoders);
- posEncodersDecoders = overrides.find(encodersDecoders.c_str(), posEncodersDecoders);
- }
- posCodec = posEncodersDecoders + encodersDecoders.size();
- AString codec = AStringPrintf(
- "\n <MediaCodec name=%s type=%s update=\"true\" >\n </MediaCodec>",
- name.c_str(),
- mime.c_str());
- overrides.insert(codec.c_str(), posCodec);
- posCodec = overrides.find(name.c_str());
- }
-
- // insert to existing entry
- ssize_t posMime = overrides.find(mime.c_str(), posCodec);
- ssize_t posEnd = overrides.find(">", posCodec);
- if (posEnd < 0) {
- ALOGE("Format error in overrides file.");
- return;
- }
- if (posMime < 0 || posMime > posEnd) {
- // new mime for an existing component
- AString codecEnd = "</MediaCodec>";
- posInsert = overrides.find(codecEnd.c_str(), posCodec) + codecEnd.size();
- AString codec = AStringPrintf(
- "\n <MediaCodec name=%s type=%s update=\"true\" >\n </MediaCodec>",
- name.c_str(),
- mime.c_str());
- overrides.insert(codec.c_str(), posInsert);
- posInsert = overrides.find(">", posInsert) + 1;
- } else {
- posInsert = posEnd + 1;
- }
-
+ AString codec =
+ AStringPrintf(" <MediaCodec name=\"%s\" type=\"%s\" update=\"true\" >\n",
+ name.c_str(),
+ mime.c_str());
+ ret.append(codec);
CodecSettings settings = results.valueAt(i);
for (size_t i = 0; i < settings.size(); ++i) {
// WARNING: we assume all the settings are "Limit". Currently we have only one type
// of setting in this case, which is "max-supported-instances".
- AString strInsert = AStringPrintf(
- "\n <Limit name=\"%s\" value=\"%s\" />",
+ AString setting = AStringPrintf(
+ " <Limit name=\"%s\" value=\"%s\" />\n",
settings.keyAt(i).c_str(),
settings.valueAt(i).c_str());
- overrides.insert(strInsert, posInsert);
+ ret.append(setting);
}
+ ret.append(" </MediaCodec>\n");
+ }
+ return ret;
+}
+
+void exportResultsToXML(
+ const char *fileName,
+ const CodecSettings& global_results,
+ const KeyedVector<AString, CodecSettings>& encoder_results,
+ const KeyedVector<AString, CodecSettings>& decoder_results) {
+ if (global_results.size() == 0 && encoder_results.size() == 0 && decoder_results.size() == 0) {
+ return;
}
- if (!LOG_NDEBUG) {
- ALOGV("New overrides:");
- printLongString(overrides.c_str(), overrides.size());
+ AString overrides;
+ overrides.append("<MediaCodecs>\n");
+ if (global_results.size() > 0) {
+ overrides.append(" <Settings>\n");
+ overrides.append(globalResultsToXml(global_results));
+ overrides.append(" </Settings>\n");
}
+ if (encoder_results.size() > 0) {
+ overrides.append(" <Encoders>\n");
+ overrides.append(codecResultsToXml(encoder_results));
+ overrides.append(" </Encoders>\n");
+ }
+ if (decoder_results.size() > 0) {
+ overrides.append(" <Decoders>\n");
+ overrides.append(codecResultsToXml(decoder_results));
+ overrides.append(" </Decoders>\n");
+ }
+ overrides.append("</MediaCodecs>\n");
- f = fopen(fileName, "wb");
+ FILE *f = fopen(fileName, "wb");
if (f == NULL) {
ALOGE("Failed to open %s for writing.", fileName);
return;
diff --git a/media/libstagefright/MediaCodecListOverrides.h b/media/libstagefright/MediaCodecListOverrides.h
index c6cc2ea..c4758fa 100644
--- a/media/libstagefright/MediaCodecListOverrides.h
+++ b/media/libstagefright/MediaCodecListOverrides.h
@@ -26,24 +26,27 @@
namespace android {
+extern const char *kProfilingResults;
+
struct MediaCodecInfo;
bool splitString(const AString &s, const AString &delimiter, AString *s1, AString *s2);
-bool splitString(
- const AString &s, const AString &delimiter, AString *s1, AString *s2, AString *s3);
+// profile codecs and save the result to xml file named kProfilingResults.
+void profileCodecs(const Vector<sp<MediaCodecInfo>> &infos);
+// profile codecs and save the result to encoder_results and decoder_results.
void profileCodecs(
const Vector<sp<MediaCodecInfo>> &infos,
- KeyedVector<AString, CodecSettings> *results,
- bool forceToMeasure = false); // forceToMeasure is mainly for testing
+ KeyedVector<AString, CodecSettings> *encoder_results,
+ KeyedVector<AString, CodecSettings> *decoder_results,
+ bool forceToMeasure = false);
-void applyCodecSettings(
- const AString& codecInfo,
- const CodecSettings &settings,
- Vector<sp<MediaCodecInfo>> *infos);
-
-void exportResultsToXML(const char *fileName, const KeyedVector<AString, CodecSettings>& results);
+void exportResultsToXML(
+ const char *fileName,
+ const CodecSettings& global_results,
+ const KeyedVector<AString, CodecSettings>& encoder_results,
+ const KeyedVector<AString, CodecSettings>& decoder_results);
} // namespace android
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 8d4bab8..aa6a7c0 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -43,6 +43,7 @@
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/OMXCodec.h>
+#include <media/stagefright/SurfaceUtils.h>
#include <media/stagefright/Utils.h>
#include <media/stagefright/SkipCutBuffer.h>
#include <utils/Vector.h>
@@ -1783,35 +1784,6 @@
return OK;
}
-status_t OMXCodec::applyRotation() {
- sp<MetaData> meta = mSource->getFormat();
-
- int32_t rotationDegrees;
- if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
- rotationDegrees = 0;
- }
-
- uint32_t transform;
- switch (rotationDegrees) {
- case 0: transform = 0; break;
- case 90: transform = HAL_TRANSFORM_ROT_90; break;
- case 180: transform = HAL_TRANSFORM_ROT_180; break;
- case 270: transform = HAL_TRANSFORM_ROT_270; break;
- default: transform = 0; break;
- }
-
- status_t err = OK;
-
- if (transform) {
- err = native_window_set_buffers_transform(
- mNativeWindow.get(), transform);
- ALOGE("native_window_set_buffers_transform failed: %s (%d)",
- strerror(-err), -err);
- }
-
- return err;
-}
-
status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
// Get the number of buffers needed.
OMX_PARAM_PORTDEFINITIONTYPE def;
@@ -1825,30 +1797,11 @@
return err;
}
- err = native_window_set_buffers_dimensions(
- mNativeWindow.get(),
- def.format.video.nFrameWidth,
- def.format.video.nFrameHeight);
+ sp<MetaData> meta = mSource->getFormat();
- if (err != 0) {
- ALOGE("native_window_set_buffers_dimensions failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_buffers_format(
- mNativeWindow.get(),
- def.format.video.eColorFormat);
-
- if (err != 0) {
- ALOGE("native_window_set_buffers_format failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = applyRotation();
- if (err != OK) {
- return err;
+ int32_t rotationDegrees;
+ if (!meta->findInt32(kKeyRotation, &rotationDegrees)) {
+ rotationDegrees = 0;
}
// Set up the native window.
@@ -1859,34 +1812,19 @@
// XXX: Currently this error is logged, but not fatal.
usage = 0;
}
+
if (mFlags & kEnableGrallocUsageProtected) {
usage |= GRALLOC_USAGE_PROTECTED;
}
- // Make sure to check whether either Stagefright or the video decoder
- // requested protected buffers.
- if (usage & GRALLOC_USAGE_PROTECTED) {
- // Verify that the ANativeWindow sends images directly to
- // SurfaceFlinger.
- int queuesToNativeWindow = 0;
- err = mNativeWindow->query(
- mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER,
- &queuesToNativeWindow);
- if (err != 0) {
- ALOGE("error authenticating native window: %d", err);
- return err;
- }
- if (queuesToNativeWindow != 1) {
- ALOGE("native window could not be authenticated");
- return PERMISSION_DENIED;
- }
- }
-
- ALOGV("native_window_set_usage usage=0x%x", usage);
- err = native_window_set_usage(
- mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
+ err = setNativeWindowSizeFormatAndUsage(
+ mNativeWindow.get(),
+ def.format.video.nFrameWidth,
+ def.format.video.nFrameHeight,
+ def.format.video.eColorFormat,
+ rotationDegrees,
+ usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP);
if (err != 0) {
- ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
return err;
}
@@ -2053,156 +1991,6 @@
return bufInfo;
}
-status_t OMXCodec::pushBlankBuffersToNativeWindow() {
- status_t err = NO_ERROR;
- ANativeWindowBuffer* anb = NULL;
- int numBufs = 0;
- int minUndequeuedBufs = 0;
-
- // We need to reconnect to the ANativeWindow as a CPU client to ensure that
- // no frames get dropped by SurfaceFlinger assuming that these are video
- // frames.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_set_buffers_dimensions(mNativeWindow.get(), 1, 1);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffers_dimensions failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = native_window_set_buffers_format(mNativeWindow.get(), HAL_PIXEL_FORMAT_RGBX_8888);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffers_format failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = native_window_set_usage(mNativeWindow.get(),
- GRALLOC_USAGE_SW_WRITE_OFTEN);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_usage failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = native_window_set_scaling_mode(mNativeWindow.get(),
- NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
- if (err != OK) {
- ALOGE("error pushing blank frames: set_scaling_mode failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = mNativeWindow->query(mNativeWindow.get(),
- NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
- "failed: %s (%d)", strerror(-err), -err);
- goto error;
- }
-
- numBufs = minUndequeuedBufs + 1;
- err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- // We push numBufs + 1 buffers to ensure that we've drawn into the same
- // buffer twice. This should guarantee that the buffer has been displayed
- // on the screen and then been replaced, so an previous video frames are
- // guaranteed NOT to be currently displayed.
- for (int i = 0; i < numBufs + 1; i++) {
- err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &anb);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
-
- // Fill the buffer with the a 1x1 checkerboard pattern ;)
- uint32_t* img = NULL;
- err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: lock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- *img = 0;
-
- err = buf->unlock();
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: unlock failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- err = mNativeWindow->queueBuffer(mNativeWindow.get(),
- buf->getNativeBuffer(), -1);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
- strerror(-err), -err);
- goto error;
- }
-
- anb = NULL;
- }
-
-error:
-
- if (err != NO_ERROR) {
- // Clean up after an error.
- if (anb != NULL) {
- mNativeWindow->cancelBuffer(mNativeWindow.get(), anb, -1);
- }
-
- native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
-
- return err;
- } else {
- // Clean up after success.
- err = native_window_api_disconnect(mNativeWindow.get(),
- NATIVE_WINDOW_API_CPU);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- err = native_window_api_connect(mNativeWindow.get(),
- NATIVE_WINDOW_API_MEDIA);
- if (err != NO_ERROR) {
- ALOGE("error pushing blank frames: api_connect failed: %s (%d)",
- strerror(-err), -err);
- return err;
- }
-
- return NO_ERROR;
- }
-}
-
int64_t OMXCodec::getDecodingTimeUs() {
CHECK(mIsEncoder && mIsVideo);
@@ -2784,7 +2572,7 @@
// them has made it to the display. This allows the OMX
// component teardown to zero out any protected buffers
// without the risk of scanning out one of those buffers.
- pushBlankBuffersToNativeWindow();
+ pushBlankBuffersToNativeWindow(mNativeWindow.get());
}
setState(IDLE_TO_LOADED);
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index d577034..4297549 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -753,7 +753,9 @@
oggpack_buffer bits;
oggpack_readinit(&bits, &ref);
- CHECK_EQ(oggpack_read(&bits, 8), type);
+ if (oggpack_read(&bits, 8) != type) {
+ return ERROR_MALFORMED;
+ }
for (size_t i = 0; i < 6; ++i) {
oggpack_read(&bits, 8); // skip 'vorbis'
}
@@ -761,7 +763,9 @@
switch (type) {
case 1:
{
- CHECK_EQ(0, _vorbis_unpack_info(&mVi, &bits));
+ if (0 != _vorbis_unpack_info(&mVi, &bits)) {
+ return ERROR_MALFORMED;
+ }
mMeta->setData(kKeyVorbisInfo, 0, data, size);
mMeta->setInt32(kKeySampleRate, mVi.rate);
diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp
new file mode 100644
index 0000000..6b62e43
--- /dev/null
+++ b/media/libstagefright/SurfaceUtils.cpp
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "SurfaceUtils"
+#include <utils/Log.h>
+
+#include <media/stagefright/SurfaceUtils.h>
+
+#include <gui/Surface.h>
+
+namespace android {
+
+status_t setNativeWindowSizeFormatAndUsage(
+ ANativeWindow *nativeWindow /* nonnull */,
+ int width, int height, int format, int rotation, int usage) {
+ status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_set_buffers_format(nativeWindow, format);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ int transform = 0;
+ if ((rotation % 90) == 0) {
+ switch ((rotation / 90) & 3) {
+ case 1: transform = HAL_TRANSFORM_ROT_90; break;
+ case 2: transform = HAL_TRANSFORM_ROT_180; break;
+ case 3: transform = HAL_TRANSFORM_ROT_270; break;
+ default: transform = 0; break;
+ }
+ }
+
+ err = native_window_set_buffers_transform(nativeWindow, transform);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ // Make sure to check whether either Stagefright or the video decoder
+ // requested protected buffers.
+ if (usage & GRALLOC_USAGE_PROTECTED) {
+ // Verify that the ANativeWindow sends images directly to
+ // SurfaceFlinger.
+ int queuesToNativeWindow = 0;
+ err = nativeWindow->query(
+ nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow);
+ if (err != NO_ERROR) {
+ ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+ if (queuesToNativeWindow != 1) {
+ ALOGE("native window could not be authenticated");
+ return PERMISSION_DENIED;
+ }
+ }
+
+ int consumerUsage = 0;
+ err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage);
+ if (err != NO_ERROR) {
+ ALOGW("failed to get consumer usage bits. ignoring");
+ err = NO_ERROR;
+ }
+
+ int finalUsage = usage | consumerUsage;
+ ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage);
+ err = native_window_set_usage(nativeWindow, finalUsage);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_set_scaling_mode(
+ nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ if (err != NO_ERROR) {
+ ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x",
+ nativeWindow, width, height, format, rotation, finalUsage);
+ return NO_ERROR;
+}
+
+status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) {
+ status_t err = NO_ERROR;
+ ANativeWindowBuffer* anb = NULL;
+ int numBufs = 0;
+ int minUndequeuedBufs = 0;
+
+ // We need to reconnect to the ANativeWindow as a CPU client to ensure that
+ // no frames get dropped by SurfaceFlinger assuming that these are video
+ // frames.
+ err = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_CPU);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
+ (void)native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ return err;
+ }
+
+ err = setNativeWindowSizeFormatAndUsage(
+ nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN);
+ if (err != NO_ERROR) {
+ goto error;
+ }
+
+ static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true);
+
+ err = nativeWindow->query(nativeWindow,
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
+ "failed: %s (%d)", strerror(-err), -err);
+ goto error;
+ }
+
+ numBufs = minUndequeuedBufs + 1;
+ err = native_window_set_buffer_count(nativeWindow, numBufs);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", strerror(-err), -err);
+ goto error;
+ }
+
+ // We push numBufs + 1 buffers to ensure that we've drawn into the same
+ // buffer twice. This should guarantee that the buffer has been displayed
+ // on the screen and then been replaced, so an previous video frames are
+ // guaranteed NOT to be currently displayed.
+ for (int i = 0; i < numBufs + 1; i++) {
+ err = native_window_dequeue_buffer_and_wait(nativeWindow, &anb);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ break;
+ }
+
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+
+ // Fill the buffer with the a 1x1 checkerboard pattern ;)
+ uint32_t *img = NULL;
+ err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: lock failed: %s (%d)", strerror(-err), -err);
+ break;
+ }
+
+ *img = 0;
+
+ err = buf->unlock();
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err);
+ break;
+ }
+
+ err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1);
+ if (err != NO_ERROR) {
+ ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err);
+ break;
+ }
+
+ anb = NULL;
+ }
+
+error:
+
+ if (anb != NULL) {
+ nativeWindow->cancelBuffer(nativeWindow, anb, -1);
+ anb = NULL;
+ }
+
+ // Clean up after success or error.
+ status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU);
+ if (err2 != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2);
+ if (err == NO_ERROR) {
+ err = err2;
+ }
+ }
+
+ err2 = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA);
+ if (err2 != NO_ERROR) {
+ ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err);
+ if (err == NO_ERROR) {
+ err = err2;
+ }
+ }
+
+ return err;
+}
+
+} // namespace android
+
diff --git a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
old mode 100644
new mode 100755
index 06b2163..6afac74
--- a/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
+++ b/media/libstagefright/codecs/avcenc/SoftAVCEnc.cpp
@@ -625,7 +625,7 @@
return errType;
}
- mStride = ALIGN16(mWidth);
+ mStride = mWidth;
if (mInputDataIsMeta) {
if (mConversionBuffer) {
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index 970acf3..e654843 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -661,7 +661,8 @@
BufferInfo *outputBufferInfo = *outputBufferInfoQueue.begin();
OMX_BUFFERHEADERTYPE *outputBufferHeader = outputBufferInfo->mHeader;
- if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ if ((inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) &&
+ inputBufferHeader->nFilledLen == 0) {
inputBufferInfoQueue.erase(inputBufferInfoQueue.begin());
inputBufferInfo->mOwnedByUs = false;
notifyEmptyBufferDone(inputBufferHeader);
@@ -762,6 +763,9 @@
encoded_packet->data.frame.sz);
outputBufferInfo->mOwnedByUs = false;
outputBufferInfoQueue.erase(outputBufferInfoQueue.begin());
+ if (inputBufferHeader->nFlags & OMX_BUFFERFLAG_EOS) {
+ outputBufferHeader->nFlags |= OMX_BUFFERFLAG_EOS;
+ }
notifyFillBufferDone(outputBufferHeader);
}
}
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 8f356b6..c559682 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -364,7 +364,7 @@
} else {
numFrames = vorbis_dsp_pcmout(
mState, (int16_t *)outHeader->pBuffer,
- kMaxNumSamplesPerBuffer);
+ (kMaxNumSamplesPerBuffer / mVi->channels));
if (numFrames < 0) {
ALOGE("vorbis_dsp_pcmout returned %d", numFrames);
diff --git a/media/libstagefright/http/MediaHTTP.cpp b/media/libstagefright/http/MediaHTTP.cpp
index bb89567..2d9b3d4 100644
--- a/media/libstagefright/http/MediaHTTP.cpp
+++ b/media/libstagefright/http/MediaHTTP.cpp
@@ -30,12 +30,11 @@
namespace android {
MediaHTTP::MediaHTTP(const sp<IMediaHTTPConnection> &conn)
- : mInitCheck(NO_INIT),
+ : mInitCheck((conn != NULL) ? OK : NO_INIT),
mHTTPConnection(conn),
mCachedSizeValid(false),
mCachedSize(0ll),
mDrmManagerClient(NULL) {
- mInitCheck = OK;
}
MediaHTTP::~MediaHTTP() {
@@ -171,6 +170,10 @@
}
String8 MediaHTTP::getUri() {
+ if (mInitCheck != OK) {
+ return String8::empty();
+ }
+
String8 uri;
if (OK == mHTTPConnection->getUri(&uri)) {
return uri;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index d8c38e7..64a8532 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -1503,11 +1503,10 @@
ALOGV("discarding fetcher-%d", fetcher->getFetcherID());
fetcher->stopAsync();
} else {
- float threshold = -1.0f; // always finish fetching by default
+ float threshold = 0.0f; // default to pause after current block (47Kbytes)
bool disconnect = false;
if (timeUs >= 0ll) {
// seeking, no need to finish fetching
- threshold = 0.0f;
disconnect = true;
} else if (delayRemoval) {
// adapting, abort if remaining of current segment is over threshold
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 53087b6..5a0deec 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -1424,11 +1424,17 @@
int64_t minDiffUs, maxDiffUs;
if (mSeekMode == LiveSession::kSeekModeNextSample) {
+ // if the previous fetcher paused in the middle of a segment, we
+ // want to start at a segment that overlaps the last sample
minDiffUs = -mPlaylist->getTargetDuration();
maxDiffUs = 0ll;
} else {
+ // if the previous fetcher paused at the end of a segment, ideally
+ // we want to start at the segment that's roughly aligned with its
+ // next segment, but if the two variants are not well aligned we
+ // adjust the diff to within (-T/2, T/2)
minDiffUs = -mPlaylist->getTargetDuration() / 2;
- maxDiffUs = mPlaylist->getTargetDuration();
+ maxDiffUs = mPlaylist->getTargetDuration() / 2;
}
int32_t oldSeqNumber = mSeqNumber;
@@ -1611,6 +1617,9 @@
ALOGE("MPEG2 Transport streams do not contain subtitles.");
return ERROR_MALFORMED;
}
+ if (stream == LiveSession::STREAMTYPE_METADATA) {
+ continue;
+ }
ATSParser::SourceType type =LiveSession::getSourceTypeForStream(stream);
sp<AnotherPacketSource> source =
static_cast<AnotherPacketSource *>(
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index f31af7b..03c9a8a 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -29,6 +29,8 @@
struct OMXMaster;
class GraphicBufferSource;
+status_t StatusFromOMXError(OMX_ERRORTYPE err);
+
struct OMXNodeInstance {
OMXNodeInstance(
OMX *owner, const sp<IOMXObserver> &observer, const char *name);
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index b9e2f9c..876abb8 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -32,6 +32,7 @@
#include "OMXMaster.h"
+#include <OMX_AsString.h>
#include <OMX_Component.h>
namespace android {
@@ -233,11 +234,11 @@
instance, &handle);
if (err != OMX_ErrorNone) {
- ALOGE("FAILED to allocate omx component '%s'", name);
+ ALOGE("FAILED to allocate omx component '%s' err=%s(%#x)", name, asString(err), err);
instance->onGetHandleFailed();
- return UNKNOWN_ERROR;
+ return StatusFromOMXError(err);
}
*node = makeNodeID(instance);
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 5bc1972..04293d6 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -220,13 +220,15 @@
return mNodeID;
}
-static status_t StatusFromOMXError(OMX_ERRORTYPE err) {
+status_t StatusFromOMXError(OMX_ERRORTYPE err) {
switch (err) {
case OMX_ErrorNone:
return OK;
case OMX_ErrorUnsupportedSetting:
case OMX_ErrorUnsupportedIndex:
return ERROR_UNSUPPORTED;
+ case OMX_ErrorInsufficientResources:
+ return NO_MEMORY;
default:
return UNKNOWN_ERROR;
}
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 00f071b..ba17e90 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -1673,21 +1673,11 @@
}
size_t n = strlen(baseURL);
- if (baseURL[n - 1] == '/') {
- out->setTo(baseURL);
- out->append(url);
- } else {
- const char *slashPos = strrchr(baseURL, '/');
-
- if (slashPos > &baseURL[6]) {
- out->setTo(baseURL, slashPos - baseURL);
- } else {
- out->setTo(baseURL);
- }
-
+ out->setTo(baseURL);
+ if (baseURL[n - 1] != '/') {
out->append("/");
- out->append(url);
}
+ out->append(url);
return true;
}
diff --git a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
index 170cde3..146a244 100644
--- a/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
+++ b/media/libstagefright/tests/MediaCodecListOverrides_test.cpp
@@ -31,29 +31,8 @@
static const char kTestOverridesStr[] =
"<MediaCodecs>\n"
" <Settings>\n"
-" <Setting name=\"max-max-supported-instances\" value=\"8\" update=\"true\" />\n"
-" </Settings>\n"
-" <Encoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"bitrate\" range=\"1-20000000\" />\n"
-" <Feature name=\"can-swap-width-height\" />\n"
-" </MediaCodec>\n"
-" </Encoders>\n"
-" <Decoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"size\" min=\"64x64\" max=\"1920x1088\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"different_mime\" update=\"true\" >\n"
-" </MediaCodec>\n"
-" </Decoders>\n"
-"</MediaCodecs>\n";
-
-static const char kTestOverridesStrNew1[] =
-"<MediaCodecs>\n"
-" <Settings>\n"
-" <Setting name=\"max-max-supported-instances\" value=\"8\" update=\"true\" />\n"
+" <Setting name=\"supports-multiple-secure-codecs\" value=\"false\" />\n"
+" <Setting name=\"supports-secure-with-non-secure-codec\" value=\"true\" />\n"
" </Settings>\n"
" <Encoders>\n"
" <MediaCodec name=\"OMX.qcom.video.encoder.avc\" type=\"video/avc\" update=\"true\" >\n"
@@ -61,57 +40,21 @@
" </MediaCodec>\n"
" <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"bitrate\" range=\"1-20000000\" />\n"
-" <Feature name=\"can-swap-width-height\" />\n"
" </MediaCodec>\n"
" </Encoders>\n"
" <Decoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
+" <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
+" <Limit name=\"max-supported-instances\" value=\"1\" />\n"
" </MediaCodec>\n"
" <MediaCodec name=\"OMX.qcom.video.decoder.h263\" type=\"video/3gpp\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"1\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-" <Quirk name=\"requires-allocate-on-input-ports\" />\n"
-" <Limit name=\"size\" min=\"64x64\" max=\"1920x1088\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"different_mime\" update=\"true\" >\n"
-" </MediaCodec>\n"
" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"video/mpeg2\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
" </MediaCodec>\n"
-" </Decoders>\n"
-"</MediaCodecs>\n";
-
-static const char kTestOverridesStrNew2[] =
-"\n"
-"<MediaCodecs>\n"
-" <Encoders>\n"
-" <MediaCodec name=\"OMX.qcom.video.encoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.encoder.avc\" type=\"video/avc\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" </MediaCodec>\n"
-" </Encoders>\n"
-" <Decoders>\n"
" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg4\" type=\"video/mp4v-es\" update=\"true\" >\n"
" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.mpeg2\" type=\"video/mpeg2\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"3\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.h263\" type=\"video/3gpp\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"4\" />\n"
-" </MediaCodec>\n"
-" <MediaCodec name=\"OMX.qcom.video.decoder.avc.secure\" type=\"video/avc\" update=\"true\" >\n"
-" <Limit name=\"max-supported-instances\" value=\"1\" />\n"
-" </MediaCodec>\n"
" </Decoders>\n"
"</MediaCodecs>\n";
@@ -119,53 +62,6 @@
public:
MediaCodecListOverridesTest() {}
- void verifyOverrides(const KeyedVector<AString, CodecSettings> &overrides) {
- EXPECT_EQ(3u, overrides.size());
-
- EXPECT_TRUE(overrides.keyAt(0) == "OMX.qcom.video.decoder.avc video/avc decoder");
- const CodecSettings &settings0 = overrides.valueAt(0);
- EXPECT_EQ(1u, settings0.size());
- EXPECT_TRUE(settings0.keyAt(0) == "max-supported-instances");
- EXPECT_TRUE(settings0.valueAt(0) == "4");
-
- EXPECT_TRUE(overrides.keyAt(1) == "OMX.qcom.video.encoder.avc video/avc encoder");
- const CodecSettings &settings1 = overrides.valueAt(1);
- EXPECT_EQ(1u, settings1.size());
- EXPECT_TRUE(settings1.keyAt(0) == "max-supported-instances");
- EXPECT_TRUE(settings1.valueAt(0) == "3");
-
- EXPECT_TRUE(overrides.keyAt(2) == "global");
- const CodecSettings &settings2 = overrides.valueAt(2);
- EXPECT_EQ(3u, settings2.size());
- EXPECT_TRUE(settings2.keyAt(0) == "max-max-supported-instances");
- EXPECT_TRUE(settings2.valueAt(0) == "8");
- EXPECT_TRUE(settings2.keyAt(1) == "supports-multiple-secure-codecs");
- EXPECT_TRUE(settings2.valueAt(1) == "false");
- EXPECT_TRUE(settings2.keyAt(2) == "supports-secure-with-non-secure-codec");
- EXPECT_TRUE(settings2.valueAt(2) == "true");
- }
-
- void verifySetting(const sp<AMessage> &details, const char *name, const char *value) {
- AString value1;
- EXPECT_TRUE(details->findString(name, &value1));
- EXPECT_TRUE(value1 == value);
- }
-
- void createTestInfos(Vector<sp<MediaCodecInfo>> *infos) {
- const char *name = "OMX.qcom.video.decoder.avc";
- const bool encoder = false;
- const char *mime = "video/avc";
- sp<MediaCodecInfo> info = new MediaCodecInfo(name, encoder, mime);
- infos->push_back(info);
- const sp<MediaCodecInfo::Capabilities> caps = info->getCapabilitiesFor(mime);
- const sp<AMessage> details = caps->getDetails();
- details->setString("cap1", "value1");
- details->setString("max-max-supported-instances", "16");
-
- info = new MediaCodecInfo("anothercodec", true, "anothermime");
- infos->push_back(info);
- }
-
void addMaxInstancesSetting(
const AString &key,
const AString &value,
@@ -175,16 +71,34 @@
results->add(key, settings);
}
- void exportTestResultsToXML(const char *fileName) {
- KeyedVector<AString, CodecSettings> r;
- addMaxInstancesSetting("OMX.qcom.video.decoder.avc.secure video/avc decoder", "1", &r);
- addMaxInstancesSetting("OMX.qcom.video.decoder.h263 video/3gpp decoder", "4", &r);
- addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg2 video/mpeg2 decoder", "3", &r);
- addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg4 video/mp4v-es decoder", "3", &r);
- addMaxInstancesSetting("OMX.qcom.video.encoder.avc video/avc encoder", "4", &r);
- addMaxInstancesSetting("OMX.qcom.video.encoder.mpeg4 video/mp4v-es encoder", "4", &r);
+ void verifyProfileResults(const KeyedVector<AString, CodecSettings> &results) {
+ EXPECT_LT(0u, results.size());
+ for (size_t i = 0; i < results.size(); ++i) {
+ AString key = results.keyAt(i);
+ CodecSettings settings = results.valueAt(i);
+ EXPECT_EQ(1u, settings.size());
+ EXPECT_TRUE(settings.keyAt(0) == "max-supported-instances");
+ AString valueS = settings.valueAt(0);
+ int32_t value = strtol(valueS.c_str(), NULL, 10);
+ EXPECT_LT(0, value);
+ ALOGV("profileCodecs results %s %s", key.c_str(), valueS.c_str());
+ }
+ }
- exportResultsToXML(fileName, r);
+ void exportTestResultsToXML(const char *fileName) {
+ CodecSettings gR;
+ gR.add("supports-multiple-secure-codecs", "false");
+ gR.add("supports-secure-with-non-secure-codec", "true");
+ KeyedVector<AString, CodecSettings> eR;
+ addMaxInstancesSetting("OMX.qcom.video.encoder.avc video/avc", "4", &eR);
+ addMaxInstancesSetting("OMX.qcom.video.encoder.mpeg4 video/mp4v-es", "4", &eR);
+ KeyedVector<AString, CodecSettings> dR;
+ addMaxInstancesSetting("OMX.qcom.video.decoder.avc.secure video/avc", "1", &dR);
+ addMaxInstancesSetting("OMX.qcom.video.decoder.h263 video/3gpp", "4", &dR);
+ addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg2 video/mpeg2", "3", &dR);
+ addMaxInstancesSetting("OMX.qcom.video.decoder.mpeg4 video/mp4v-es", "3", &dR);
+
+ exportResultsToXML(fileName, gR, eR, dR);
}
};
@@ -198,18 +112,6 @@
EXPECT_TRUE(splitString(s, delimiter, &s1, &s2));
EXPECT_TRUE(s1 == "abc");
EXPECT_TRUE(s2 == "123");
-
- s = "abc123xyz";
- delimiter = ",";
- AString s3;
- EXPECT_FALSE(splitString(s, delimiter, &s1, &s2, &s3));
- s = "abc,123xyz";
- EXPECT_FALSE(splitString(s, delimiter, &s1, &s2, &s3));
- s = "abc,123,xyz";
- EXPECT_TRUE(splitString(s, delimiter, &s1, &s2, &s3));
- EXPECT_TRUE(s1 == "abc");
- EXPECT_TRUE(s2 == "123" );
- EXPECT_TRUE(s3 == "xyz");
}
// TODO: the codec component never returns OMX_EventCmdComplete in unit test.
@@ -219,76 +121,14 @@
for (size_t i = 0; i < list->countCodecs(); ++i) {
infos.push_back(list->getCodecInfo(i));
}
- KeyedVector<AString, CodecSettings> results;
- profileCodecs(infos, &results, true /* forceToMeasure */);
- EXPECT_LT(0u, results.size());
- for (size_t i = 0; i < results.size(); ++i) {
- AString key = results.keyAt(i);
- CodecSettings settings = results.valueAt(i);
- EXPECT_EQ(1u, settings.size());
- EXPECT_TRUE(settings.keyAt(0) == "max-supported-instances");
- AString valueS = settings.valueAt(0);
- int32_t value = strtol(valueS.c_str(), NULL, 10);
- EXPECT_LT(0, value);
- ALOGV("profileCodecs results %s %s", key.c_str(), valueS.c_str());
- }
+ KeyedVector<AString, CodecSettings> encoder_results;
+ KeyedVector<AString, CodecSettings> decoder_results;
+ profileCodecs(infos, &encoder_results, &decoder_results, true /* forceToMeasure */);
+ verifyProfileResults(encoder_results);
+ verifyProfileResults(decoder_results);
}
-TEST_F(MediaCodecListOverridesTest, applyCodecSettings) {
- AString codecInfo = "OMX.qcom.video.decoder.avc video/avc decoder";
- Vector<sp<MediaCodecInfo>> infos;
- createTestInfos(&infos);
- CodecSettings settings;
- settings.add("max-supported-instances", "3");
- settings.add("max-max-supported-instances", "8");
- applyCodecSettings(codecInfo, settings, &infos);
-
- EXPECT_EQ(2u, infos.size());
- EXPECT_TRUE(AString(infos[0]->getCodecName()) == "OMX.qcom.video.decoder.avc");
- const sp<AMessage> details = infos[0]->getCapabilitiesFor("video/avc")->getDetails();
- verifySetting(details, "max-supported-instances", "3");
- verifySetting(details, "max-max-supported-instances", "8");
-
- EXPECT_TRUE(AString(infos[1]->getCodecName()) == "anothercodec");
- EXPECT_EQ(0u, infos[1]->getCapabilitiesFor("anothermime")->getDetails()->countEntries());
-}
-
-TEST_F(MediaCodecListOverridesTest, exportResultsToExistingFile) {
- const char *fileName = "/sdcard/mediacodec_list_overrides_test.xml";
- remove(fileName);
-
- FILE *f = fopen(fileName, "wb");
- if (f == NULL) {
- ALOGW("Failed to open %s for writing.", fileName);
- return;
- }
- EXPECT_EQ(
- strlen(kTestOverridesStr),
- fwrite(kTestOverridesStr, 1, strlen(kTestOverridesStr), f));
- fclose(f);
-
- exportTestResultsToXML(fileName);
-
- // verify
- AString overrides;
- f = fopen(fileName, "rb");
- ASSERT_TRUE(f != NULL);
- fseek(f, 0, SEEK_END);
- long size = ftell(f);
- rewind(f);
-
- char *buf = (char *)malloc(size);
- EXPECT_EQ((size_t)1, fread(buf, size, 1, f));
- overrides.setTo(buf, size);
- fclose(f);
- free(buf);
-
- EXPECT_TRUE(overrides == kTestOverridesStrNew1);
-
- remove(fileName);
-}
-
-TEST_F(MediaCodecListOverridesTest, exportResultsToEmptyFile) {
+TEST_F(MediaCodecListOverridesTest, exportTestResultsToXML) {
const char *fileName = "/sdcard/mediacodec_list_overrides_test.xml";
remove(fileName);
@@ -308,7 +148,7 @@
fclose(f);
free(buf);
- EXPECT_TRUE(overrides == kTestOverridesStrNew2);
+ EXPECT_TRUE(overrides == kTestOverridesStr);
remove(fileName);
}
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index bd6889d..485e320 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1425,6 +1425,7 @@
size_t *frameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
+ int clientUid,
int *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
@@ -1494,8 +1495,7 @@
// TODO: the uid should be passed in as a parameter to openRecord
recordTrack = thread->createRecordTrack_l(client, sampleRate, format, channelMask,
frameCount, lSessionId, notificationFrames,
- IPCThreadState::self()->getCallingUid(),
- flags, tid, &lStatus);
+ clientUid, flags, tid, &lStatus);
LOG_ALWAYS_FATAL_IF((lStatus == NO_ERROR) && (recordTrack == 0));
if (lStatus == NO_ERROR) {
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 8085ec2..51b2610 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -124,6 +124,7 @@
size_t *pFrameCount,
IAudioFlinger::track_flags_t *flags,
pid_t tid,
+ int clientUid,
int *sessionId,
size_t *notificationFrames,
sp<IMemory>& cblk,
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 7040af4..193fd64 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -66,9 +66,9 @@
#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0]))
#endif
-// Set kUseNewMixer to true to use the new mixer engine always. Otherwise the
-// original code will be used for stereo sinks, the new mixer for multichannel.
-static const bool kUseNewMixer = true;
+// Set kUseNewMixer to true to use the new mixer engine. Otherwise the
+// original code will be used. This is false for now.
+static const bool kUseNewMixer = false;
// Set kUseFloat to true to allow floating input into the mixer engine.
// If kUseNewMixer is false, this is ignored or may be overridden internally
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 8b8dd78..2c4d801 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -500,6 +500,7 @@
// mName will be set by concrete (non-virtual) subclass
mDeathRecipient(new PMDeathRecipient(this))
{
+ memset(&mPatch, 0, sizeof(struct audio_patch));
}
AudioFlinger::ThreadBase::~ThreadBase()
@@ -1930,6 +1931,7 @@
switch (event) {
case AUDIO_OUTPUT_OPENED:
case AUDIO_OUTPUT_CONFIG_CHANGED:
+ desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;
desc->mSamplingRate = mSampleRate;
desc->mFormat = mFormat;
@@ -3002,6 +3004,7 @@
mEffectChains[i]->setDevice_l(type);
}
mOutDevice = type;
+ mPatch = *patch;
if (mOutput->audioHwDev->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
audio_hw_device_t *hwDevice = mOutput->audioHwDev->hwDevice();
@@ -3028,6 +3031,7 @@
param.toString().string());
*handle = AUDIO_PATCH_HANDLE_NONE;
}
+ sendIoConfigEvent_l(AUDIO_OUTPUT_CONFIG_CHANGED);
return status;
}
@@ -6727,6 +6731,7 @@
switch (event) {
case AUDIO_INPUT_OPENED:
case AUDIO_INPUT_CONFIG_CHANGED:
+ desc->mPatch = mPatch;
desc->mChannelMask = mChannelMask;
desc->mSamplingRate = mSampleRate;
desc->mFormat = mFormat;
@@ -6884,6 +6889,7 @@
// store new device and send to effects
mInDevice = patch->sources[0].ext.device.type;
+ mPatch = *patch;
for (size_t i = 0; i < mEffectChains.size(); i++) {
mEffectChains[i]->setDevice_l(mInDevice);
}
@@ -6936,6 +6942,8 @@
*handle = AUDIO_PATCH_HANDLE_NONE;
}
+ sendIoConfigEvent_l(AUDIO_INPUT_CONFIG_CHANGED);
+
return status;
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8167bd1..0a5597f 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -426,6 +426,7 @@
bool mStandby; // Whether thread is currently in standby.
audio_devices_t mOutDevice; // output device
audio_devices_t mInDevice; // input device
+ struct audio_patch mPatch;
audio_source_t mAudioSource;
const audio_io_handle_t mId;
diff --git a/services/audiopolicy/common/include/policy.h b/services/audiopolicy/common/include/policy.h
index a2327ee..e6a767f 100755
--- a/services/audiopolicy/common/include/policy.h
+++ b/services/audiopolicy/common/include/policy.h
@@ -60,7 +60,7 @@
*
* @return true if the device is a virtual one, false otherwise.
*/
-static bool is_virtual_input_device(audio_devices_t device)
+static inline bool is_virtual_input_device(audio_devices_t device)
{
if ((device & AUDIO_DEVICE_BIT_IN) != 0) {
device &= ~AUDIO_DEVICE_BIT_IN;
@@ -78,7 +78,7 @@
*
* @return true if the device needs distinguish on address, false otherwise..
*/
-static bool device_distinguishes_on_address(audio_devices_t device)
+static inline bool device_distinguishes_on_address(audio_devices_t device)
{
return ((device & APM_AUDIO_DEVICE_MATCH_ADDRESS_ALL & ~AUDIO_DEVICE_BIT_IN) != 0);
}
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index aa37eec..d1a2f4f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -29,7 +29,7 @@
class DeviceDescriptor : public AudioPort, public AudioPortConfig
{
public:
- DeviceDescriptor(const String8& name, audio_devices_t type);
+ DeviceDescriptor(audio_devices_t type);
virtual ~DeviceDescriptor() {}
@@ -50,10 +50,9 @@
status_t dump(int fd, int spaces, int index) const;
void log() const;
+ String8 mTag;
String8 mAddress;
- static String8 emptyNameStr;
-
private:
audio_devices_t mDeviceType;
audio_port_handle_t mId;
@@ -73,12 +72,12 @@
audio_devices_t types() const { return mDeviceTypes; }
void loadDevicesFromType(audio_devices_t types);
- void loadDevicesFromName(char *name, const DeviceVector& declaredDevices);
+ 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> getDeviceFromName(const String8& name) const;
+ sp<DeviceDescriptor> getDeviceFromTag(const String8& tag) const;
DeviceVector getDevicesFromTypeAddr(audio_devices_t type, String8 address) const;
audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 9ab1d61..89ef045 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -218,7 +218,7 @@
node = node->first_child;
while (node) {
if (strcmp(ATTACHED_OUTPUT_DEVICES_TAG, node->name) == 0) {
- availableOutputDevices.loadDevicesFromName((char *)node->value,
+ availableOutputDevices.loadDevicesFromTag((char *)node->value,
declaredDevices);
ALOGV("loadGlobalConfig() Attached Output Devices %08x",
availableOutputDevices.types());
@@ -228,13 +228,13 @@
ARRAY_SIZE(sDeviceTypeToEnumTable),
(char *)node->value);
if (device != AUDIO_DEVICE_NONE) {
- defaultOutputDevice = new DeviceDescriptor(String8("default-output"), device);
+ defaultOutputDevice = new DeviceDescriptor(device);
} else {
ALOGW("loadGlobalConfig() default device not specified");
}
ALOGV("loadGlobalConfig() mDefaultOutputDevice %08x", defaultOutputDevice->type());
} else if (strcmp(ATTACHED_INPUT_DEVICES_TAG, node->name) == 0) {
- availableInputDevices.loadDevicesFromName((char *)node->value,
+ availableInputDevices.loadDevicesFromTag((char *)node->value,
declaredDevices);
ALOGV("loadGlobalConfig() Available InputDevices %08x", availableInputDevices.types());
} else if (strcmp(SPEAKER_DRC_ENABLED_TAG, node->name) == 0) {
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 0715eea..797077a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -24,13 +24,11 @@
namespace android {
-String8 DeviceDescriptor::emptyNameStr = String8("");
-
-DeviceDescriptor::DeviceDescriptor(const String8& name, audio_devices_t type) :
- AudioPort(name, AUDIO_PORT_TYPE_DEVICE,
+DeviceDescriptor::DeviceDescriptor(audio_devices_t type) :
+ AudioPort(String8(""), AUDIO_PORT_TYPE_DEVICE,
audio_is_output_device(type) ? AUDIO_PORT_ROLE_SINK :
AUDIO_PORT_ROLE_SOURCE),
- mAddress(""), mDeviceType(type), mId(0)
+ mTag(""), mAddress(""), mDeviceType(type), mId(0)
{
}
@@ -142,24 +140,21 @@
uint32_t i = 31 - __builtin_clz(types);
uint32_t type = 1 << i;
types &= ~type;
- add(new DeviceDescriptor(String8("device_type"), type | role_bit));
+ add(new DeviceDescriptor(type | role_bit));
}
}
-void DeviceVector::loadDevicesFromName(char *name,
+void DeviceVector::loadDevicesFromTag(char *tag,
const DeviceVector& declaredDevices)
{
- char *devName = strtok(name, "|");
- while (devName != NULL) {
- if (strlen(devName) != 0) {
+ char *devTag = strtok(tag, "|");
+ while (devTag != NULL) {
+ if (strlen(devTag) != 0) {
audio_devices_t type = ConfigParsingUtils::stringToEnum(sDeviceTypeToEnumTable,
ARRAY_SIZE(sDeviceTypeToEnumTable),
- devName);
+ devTag);
if (type != AUDIO_DEVICE_NONE) {
- devName = (char *)ConfigParsingUtils::enumToString(sDeviceNameToEnumTable,
- ARRAY_SIZE(sDeviceNameToEnumTable),
- type);
- sp<DeviceDescriptor> dev = new DeviceDescriptor(String8(devName), type);
+ sp<DeviceDescriptor> dev = new DeviceDescriptor(type);
if (type == AUDIO_DEVICE_IN_REMOTE_SUBMIX ||
type == AUDIO_DEVICE_OUT_REMOTE_SUBMIX ) {
dev->mAddress = String8("0");
@@ -167,13 +162,13 @@
add(dev);
} else {
sp<DeviceDescriptor> deviceDesc =
- declaredDevices.getDeviceFromName(String8(devName));
+ declaredDevices.getDeviceFromTag(String8(devTag));
if (deviceDesc != 0) {
add(deviceDesc);
}
}
}
- devName = strtok(NULL, "|");
+ devTag = strtok(NULL, "|");
}
}
@@ -239,11 +234,11 @@
return devices;
}
-sp<DeviceDescriptor> DeviceVector::getDeviceFromName(const String8& name) const
+sp<DeviceDescriptor> DeviceVector::getDeviceFromTag(const String8& tag) const
{
sp<DeviceDescriptor> device;
for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->mName == name) {
+ if (itemAt(i)->mTag == tag) {
device = itemAt(i);
break;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index e955447..7e2050b 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -58,7 +58,7 @@
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
profile->loadInChannels((char *)node->value);
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
- profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
+ profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
mDeclaredDevices);
} else if (strcmp(node->name, FLAGS_TAG) == 0) {
profile->mFlags = ConfigParsingUtils::parseInputFlagNames((char *)node->value);
@@ -105,7 +105,7 @@
} else if (strcmp(node->name, CHANNELS_TAG) == 0) {
profile->loadOutChannels((char *)node->value);
} else if (strcmp(node->name, DEVICES_TAG) == 0) {
- profile->mSupportedDevices.loadDevicesFromName((char *)node->value,
+ profile->mSupportedDevices.loadDevicesFromTag((char *)node->value,
mDeclaredDevices);
} else if (strcmp(node->name, FLAGS_TAG) == 0) {
profile->mFlags = ConfigParsingUtils::parseOutputFlagNames((char *)node->value);
@@ -154,7 +154,8 @@
ALOGW("loadDevice() bad type %08x", type);
return BAD_VALUE;
}
- sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(String8(root->name), type);
+ sp<DeviceDescriptor> deviceDesc = new DeviceDescriptor(type);
+ deviceDesc->mTag = String8(root->name);
node = root->first_child;
while (node) {
@@ -172,8 +173,8 @@
node = node->next;
}
- ALOGV("loadDevice() adding device name %s type %08x address %s",
- deviceDesc->mName.string(), type, deviceDesc->mAddress.string());
+ ALOGV("loadDevice() adding device tag %s type %08x address %s",
+ deviceDesc->mTag.string(), type, deviceDesc->mAddress.string());
mDeclaredDevices.add(deviceDesc);
@@ -189,7 +190,7 @@
profile->mChannelMasks.add(config->channel_mask);
profile->mFormats.add(config->format);
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(name, device);
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
profile->mSupportedDevices.add(devDesc);
@@ -220,7 +221,7 @@
profile->mChannelMasks.add(config->channel_mask);
profile->mFormats.add(config->format);
- sp<DeviceDescriptor> devDesc = new DeviceDescriptor(name, device);
+ sp<DeviceDescriptor> devDesc = new DeviceDescriptor(device);
devDesc->mAddress = address;
profile->mSupportedDevices.add(devDesc);
@@ -350,7 +351,8 @@
}
sp<DeviceDescriptor> devDesc =
- new DeviceDescriptor(String8(device_name != NULL ? device_name : ""), device);
+ new DeviceDescriptor(device);
+ devDesc->mName = device_name;
devDesc->mAddress = address;
return devDesc;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index b7eed62..0c02d93 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -2648,7 +2648,7 @@
mUidCached = getuid();
mpClientInterface = clientInterface;
- mDefaultOutputDevice = new DeviceDescriptor(String8("Speaker"), AUDIO_DEVICE_OUT_SPEAKER);
+ mDefaultOutputDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPEAKER);
if (ConfigParsingUtils::loadAudioPolicyConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE,
mHwModules, mAvailableInputDevices, mAvailableOutputDevices,
mDefaultOutputDevice, mSpeakerDrcEnabled) != NO_ERROR) {
@@ -4738,7 +4738,7 @@
sp<HwModule> module;
sp<IOProfile> profile;
sp<DeviceDescriptor> defaultInputDevice =
- new DeviceDescriptor(String8("builtin-mic"), AUDIO_DEVICE_IN_BUILTIN_MIC);
+ new DeviceDescriptor(AUDIO_DEVICE_IN_BUILTIN_MIC);
mAvailableOutputDevices.add(mDefaultOutputDevice);
mAvailableInputDevices.add(defaultInputDevice);
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index bf1692d..9c4f9cd 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -128,7 +128,6 @@
List<const CameraMetadata> metadataRequestList;
int32_t requestId = mRequestIdCounter;
uint32_t loopCounter = 0;
- bool isReprocess = false;
for (List<sp<CaptureRequest> >::iterator it = requests.begin(); it != requests.end(); ++it) {
sp<CaptureRequest> request = *it;
@@ -136,18 +135,15 @@
ALOGE("%s: Camera %d: Sent null request.",
__FUNCTION__, mCameraId);
return BAD_VALUE;
- } else if (it == requests.begin()) {
- isReprocess = request->mIsReprocess;
- if (isReprocess && !mInputStream.configured) {
- ALOGE("%s: Camera %d: no input stream is configured.");
+ } else if (request->mIsReprocess) {
+ if (!mInputStream.configured) {
+ ALOGE("%s: Camera %d: no input stream is configured.", __FUNCTION__, mCameraId);
return BAD_VALUE;
- } else if (isReprocess && streaming) {
- ALOGE("%s: Camera %d: streaming reprocess requests not supported.");
+ } else if (streaming) {
+ ALOGE("%s: Camera %d: streaming reprocess requests not supported.", __FUNCTION__,
+ mCameraId);
return BAD_VALUE;
}
- } else if (isReprocess != request->mIsReprocess) {
- ALOGE("%s: Camera %d: Sent regular and reprocess requests.");
- return BAD_VALUE;
}
CameraMetadata metadata(request->mMetadata);
@@ -196,7 +192,7 @@
metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
outputStreamIds.size());
- if (isReprocess) {
+ if (request->mIsReprocess) {
metadata.update(ANDROID_REQUEST_INPUT_STREAMS, &mInputStream.id, 1);
}
diff --git a/services/camera/libcameraservice/common/CameraModule.cpp b/services/camera/libcameraservice/common/CameraModule.cpp
index ac4d9a6..064ff71 100644
--- a/services/camera/libcameraservice/common/CameraModule.cpp
+++ b/services/camera/libcameraservice/common/CameraModule.cpp
@@ -36,12 +36,47 @@
chars.update(ANDROID_CONTROL_AE_LOCK_AVAILABLE, &data, /*count*/1);
data = ANDROID_CONTROL_AWB_LOCK_AVAILABLE_TRUE;
chars.update(ANDROID_CONTROL_AWB_LOCK_AVAILABLE, &data, /*count*/1);
- controlModes.push(ANDROID_CONTROL_MODE_OFF);
controlModes.push(ANDROID_CONTROL_MODE_AUTO);
camera_metadata_entry entry = chars.find(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
if (entry.count > 1 || entry.data.u8[0] != ANDROID_CONTROL_SCENE_MODE_DISABLED) {
controlModes.push(ANDROID_CONTROL_MODE_USE_SCENE_MODE);
}
+
+ // Only advertise CONTROL_OFF mode if 3A manual controls are supported.
+ bool isManualAeSupported = false;
+ bool isManualAfSupported = false;
+ bool isManualAwbSupported = false;
+ entry = chars.find(ANDROID_CONTROL_AE_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AE_MODE_OFF) {
+ isManualAeSupported = true;
+ break;
+ }
+ }
+ }
+ entry = chars.find(ANDROID_CONTROL_AF_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AF_MODE_OFF) {
+ isManualAfSupported = true;
+ break;
+ }
+ }
+ }
+ entry = chars.find(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
+ if (entry.count > 0) {
+ for (size_t i = 0; i < entry.count; i++) {
+ if (entry.data.u8[i] == ANDROID_CONTROL_AWB_MODE_OFF) {
+ isManualAwbSupported = true;
+ break;
+ }
+ }
+ }
+ if (isManualAeSupported && isManualAfSupported && isManualAwbSupported) {
+ controlModes.push(ANDROID_CONTROL_MODE_OFF);
+ }
+
chars.update(ANDROID_CONTROL_AVAILABLE_MODES, controlModes);
}
return;
@@ -86,7 +121,7 @@
if (ret != 0) {
return ret;
}
- int deviceVersion = cameraInfo.device_version;
+ int deviceVersion = rawInfo.device_version;
if (deviceVersion < CAMERA_DEVICE_API_VERSION_2_0) {
// static_camera_characteristics is invalid
*info = rawInfo;
diff --git a/services/camera/libcameraservice/device3/Camera3InputStream.cpp b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
index 84c5754..2504bfd 100644
--- a/services/camera/libcameraservice/device3/Camera3InputStream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3InputStream.cpp
@@ -187,6 +187,8 @@
assert(mBuffersInFlight.size() == 0);
+ mConsumer->abandon();
+
/**
* no-op since we can't disconnect the producer from the consumer-side
*/