diff options
107 files changed, 2278 insertions, 788 deletions
diff --git a/cmds/stagefright/Android.mk b/cmds/stagefright/Android.mk index 0e3bc68..20c0094 100644 --- a/cmds/stagefright/Android.mk +++ b/cmds/stagefright/Android.mk @@ -17,7 +17,8 @@ LOCAL_C_INCLUDES:= \ $(TOP)/frameworks/native/include/media/openmax \ external/jpeg \ -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -40,7 +41,8 @@ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -63,7 +65,8 @@ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -87,7 +90,8 @@ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -110,7 +114,8 @@ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -133,7 +138,8 @@ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -157,7 +163,8 @@ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -199,7 +206,8 @@ LOCAL_C_INCLUDES += $(intermediates) LOCAL_STATIC_LIBRARIES:= \ libstagefright_mediafilter -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional @@ -222,7 +230,8 @@ LOCAL_C_INCLUDES:= \ frameworks/av/media/libstagefright \ $(TOP)/frameworks/native/include/media/openmax -LOCAL_CFLAGS += -Wno-multichar +LOCAL_CFLAGS += -Wno-multichar -Werror -Wall +LOCAL_CLANG := true LOCAL_MODULE_TAGS := optional diff --git a/cmds/stagefright/SimplePlayer.cpp b/cmds/stagefright/SimplePlayer.cpp index ac1a547..50913cd 100644 --- a/cmds/stagefright/SimplePlayer.cpp +++ b/cmds/stagefright/SimplePlayer.cpp @@ -21,6 +21,7 @@ #include "SimplePlayer.h" #include <gui/Surface.h> + #include <media/AudioTrack.h> #include <media/ICrypto.h> #include <media/IMediaHTTPService.h> @@ -29,7 +30,6 @@ #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/MediaCodec.h> #include <media/stagefright/MediaErrors.h> -#include <media/stagefright/NativeWindowWrapper.h> #include <media/stagefright/NuMediaExtractor.h> namespace android { @@ -73,8 +73,7 @@ status_t SimplePlayer::setSurface(const sp<IGraphicBufferProducer> &bufferProduc surface = new Surface(bufferProducer); } - msg->setObject( - "native-window", new NativeWindowWrapper(surface)); + msg->setObject("surface", surface); sp<AMessage> response; return PostAndAwaitResponse(msg, &response); @@ -132,10 +131,8 @@ void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { err = INVALID_OPERATION; } else { sp<RefBase> obj; - CHECK(msg->findObject("native-window", &obj)); - - mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get()); - + CHECK(msg->findObject("surface", &obj)); + mSurface = static_cast<Surface *>(obj.get()); err = OK; } @@ -324,7 +321,7 @@ status_t SimplePlayer::onPrepare() { err = state->mCodec->configure( format, - isVideo ? mNativeWindow->getSurfaceTextureClient() : NULL, + isVideo ? mSurface : NULL, NULL /* crypto */, 0 /* flags */); @@ -411,7 +408,7 @@ status_t SimplePlayer::onReset() { mStateByTrackIndex.clear(); mCodecLooper.clear(); mExtractor.clear(); - mNativeWindow.clear(); + mSurface.clear(); mPath.clear(); return OK; @@ -428,12 +425,12 @@ status_t SimplePlayer::onDoMoreStuff() { err = state->mCodec->dequeueInputBuffer(&index); if (err == OK) { - ALOGV("dequeued input buffer on track %d", + ALOGV("dequeued input buffer on track %zu", mStateByTrackIndex.keyAt(i)); state->mAvailInputBufferIndices.push_back(index); } else { - ALOGV("dequeueInputBuffer on track %d returned %d", + ALOGV("dequeueInputBuffer on track %zu returned %d", mStateByTrackIndex.keyAt(i), err); } } while (err == OK); @@ -448,7 +445,7 @@ status_t SimplePlayer::onDoMoreStuff() { &info.mFlags); if (err == OK) { - ALOGV("dequeued output buffer on track %d", + ALOGV("dequeued output buffer on track %zu", mStateByTrackIndex.keyAt(i)); state->mAvailOutputBufferInfos.push_back(info); @@ -459,7 +456,7 @@ status_t SimplePlayer::onDoMoreStuff() { err = state->mCodec->getOutputBuffers(&state->mBuffers[1]); CHECK_EQ(err, (status_t)OK); } else { - ALOGV("dequeueOutputBuffer on track %d returned %d", + ALOGV("dequeueOutputBuffer on track %zu returned %d", mStateByTrackIndex.keyAt(i), err); } } while (err == OK @@ -502,7 +499,7 @@ status_t SimplePlayer::onDoMoreStuff() { 0); CHECK_EQ(err, (status_t)OK); - ALOGV("enqueued input data on track %d", trackIndex); + ALOGV("enqueued input data on track %zu", trackIndex); err = mExtractor->advance(); CHECK_EQ(err, (status_t)OK); @@ -528,8 +525,8 @@ status_t SimplePlayer::onDoMoreStuff() { bool release = true; if (lateByUs > 30000ll) { - ALOGI("track %d buffer late by %lld us, dropping.", - mStateByTrackIndex.keyAt(i), lateByUs); + ALOGI("track %zu buffer late by %lld us, dropping.", + mStateByTrackIndex.keyAt(i), (long long)lateByUs); state->mCodec->releaseOutputBuffer(info->mIndex); } else { if (state->mAudioTrack != NULL) { @@ -558,8 +555,8 @@ status_t SimplePlayer::onDoMoreStuff() { break; } } else { - ALOGV("track %d buffer early by %lld us.", - mStateByTrackIndex.keyAt(i), -lateByUs); + ALOGV("track %zu buffer early by %lld us.", + mStateByTrackIndex.keyAt(i), (long long)-lateByUs); break; } } @@ -569,7 +566,7 @@ status_t SimplePlayer::onDoMoreStuff() { } status_t SimplePlayer::onOutputFormatChanged( - size_t trackIndex, CodecState *state) { + size_t trackIndex __unused, CodecState *state) { sp<AMessage> format; status_t err = state->mCodec->getOutputFormat(&format); @@ -640,7 +637,7 @@ void SimplePlayer::renderAudio( if (delayUs > 2000ll) { ALOGW("AudioTrack::write took %lld us, numFramesAvailableToWrite=%u, " "numFramesWritten=%u", - delayUs, numFramesAvailableToWrite, numFramesWritten); + (long long)delayUs, numFramesAvailableToWrite, numFramesWritten); } info->mOffset += nbytes; diff --git a/cmds/stagefright/SimplePlayer.h b/cmds/stagefright/SimplePlayer.h index ce993e8..ae9dfd2 100644 --- a/cmds/stagefright/SimplePlayer.h +++ b/cmds/stagefright/SimplePlayer.h @@ -25,8 +25,8 @@ struct ALooper; struct AudioTrack; class IGraphicBufferProducer; struct MediaCodec; -struct NativeWindowWrapper; struct NuMediaExtractor; +class Surface; struct SimplePlayer : public AHandler { SimplePlayer(); @@ -84,7 +84,7 @@ private: State mState; AString mPath; - sp<NativeWindowWrapper> mNativeWindow; + sp<Surface> mSurface; sp<NuMediaExtractor> mExtractor; sp<ALooper> mCodecLooper; diff --git a/cmds/stagefright/audioloop.cpp b/cmds/stagefright/audioloop.cpp index 7b0de24..6e9e6ec 100644 --- a/cmds/stagefright/audioloop.cpp +++ b/cmds/stagefright/audioloop.cpp @@ -18,6 +18,8 @@ #include <sys/stat.h> #include <fcntl.h> +#include <utils/String16.h> + #include <binder/ProcessState.h> #include <media/mediarecorder.h> #include <media/stagefright/foundation/ADebug.h> @@ -34,7 +36,7 @@ using namespace android; static void usage(const char* name) { - fprintf(stderr, "Usage: %s [-d duration] [-m] [-w] [<output-file>]\n", name); + fprintf(stderr, "Usage: %s [-d du.ration] [-m] [-w] [<output-file>]\n", name); fprintf(stderr, "Encodes either a sine wave or microphone input to AMR format\n"); fprintf(stderr, " -d duration in seconds, default 5 seconds\n"); fprintf(stderr, " -m use microphone for input, default sine source\n"); @@ -85,6 +87,7 @@ int main(int argc, char* argv[]) // talk into the appropriate microphone for the duration source = new AudioSource( AUDIO_SOURCE_MIC, + String16(), kSampleRate, channels); } else { diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp index d987250..dae9bbe 100644 --- a/cmds/stagefright/codec.cpp +++ b/cmds/stagefright/codec.cpp @@ -108,7 +108,7 @@ static int decode( continue; } - ALOGV("selecting track %d", i); + ALOGV("selecting track %zu", i); err = extractor->selectTrack(i); CHECK_EQ(err, (status_t)OK); @@ -151,7 +151,7 @@ static int decode( CHECK_EQ((status_t)OK, codec->getInputBuffers(&state->mInBuffers)); CHECK_EQ((status_t)OK, codec->getOutputBuffers(&state->mOutBuffers)); - ALOGV("got %d input and %d output buffers", + ALOGV("got %zu input and %zu output buffers", state->mInBuffers.size(), state->mOutBuffers.size()); } @@ -172,7 +172,7 @@ static int decode( err = state->mCodec->dequeueInputBuffer(&index, kTimeout); if (err == OK) { - ALOGV("filling input buffer %d", index); + ALOGV("filling input buffer %zu", index); const sp<ABuffer> &buffer = state->mInBuffers.itemAt(index); @@ -209,7 +209,7 @@ static int decode( state->mCodec->dequeueInputBuffer(&index, kTimeout); if (err == OK) { - ALOGV("signalling input EOS on track %d", i); + ALOGV("signalling input EOS on track %zu", i); err = state->mCodec->queueInputBuffer( index, @@ -258,8 +258,8 @@ static int decode( kTimeout); if (err == OK) { - ALOGV("draining output buffer %d, time = %lld us", - index, presentationTimeUs); + ALOGV("draining output buffer %zu, time = %lld us", + index, (long long)presentationTimeUs); ++state->mNumBuffersDecoded; state->mNumBytesDecoded += size; @@ -293,7 +293,7 @@ static int decode( CHECK_EQ((status_t)OK, state->mCodec->getOutputBuffers(&state->mOutBuffers)); - ALOGV("got %d output buffers", state->mOutBuffers.size()); + ALOGV("got %zu output buffers", state->mOutBuffers.size()); } else if (err == INFO_FORMAT_CHANGED) { sp<AMessage> format; CHECK_EQ((status_t)OK, state->mCodec->getOutputFormat(&format)); @@ -313,17 +313,17 @@ static int decode( CHECK_EQ((status_t)OK, state->mCodec->release()); if (state->mIsAudio) { - printf("track %zu: %" PRId64 " bytes received. %.2f KB/sec\n", + printf("track %zu: %lld bytes received. %.2f KB/sec\n", i, - state->mNumBytesDecoded, + (long long)state->mNumBytesDecoded, state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); } else { - printf("track %zu: %" PRId64 " frames decoded, %.2f fps. %" PRId64 + printf("track %zu: %lld frames decoded, %.2f fps. %lld" " bytes received. %.2f KB/sec\n", i, - state->mNumBuffersDecoded, + (long long)state->mNumBuffersDecoded, state->mNumBuffersDecoded * 1E6 / elapsedTimeUs, - state->mNumBytesDecoded, + (long long)state->mNumBytesDecoded, state->mNumBytesDecoded * 1E6 / 1024 / elapsedTimeUs); } } @@ -418,7 +418,7 @@ int main(int argc, char **argv) { ssize_t displayWidth = info.w; ssize_t displayHeight = info.h; - ALOGV("display is %ld x %ld\n", displayWidth, displayHeight); + ALOGV("display is %zd x %zd\n", displayWidth, displayHeight); control = composerClient->createSurface( String8("A Surface"), diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp index f77b38b..1183112 100644 --- a/cmds/stagefright/mediafilter.cpp +++ b/cmds/stagefright/mediafilter.cpp @@ -81,7 +81,7 @@ struct SaturationRSFilter : RenderScriptWrapper::RSFilterCallback { return OK; } - status_t handleSetParameters(const sp<AMessage> &msg) { + status_t handleSetParameters(const sp<AMessage> &msg __unused) { return OK; } @@ -101,7 +101,7 @@ struct NightVisionRSFilter : RenderScriptWrapper::RSFilterCallback { return OK; } - status_t handleSetParameters(const sp<AMessage> &msg) { + status_t handleSetParameters(const sp<AMessage> &msg __unused) { return OK; } @@ -121,7 +121,7 @@ struct ARGBToRGBARSFilter : RenderScriptWrapper::RSFilterCallback { return OK; } - status_t handleSetParameters(const sp<AMessage> &msg) { + status_t handleSetParameters(const sp<AMessage> &msg __unused) { return OK; } @@ -597,7 +597,7 @@ static int decode( if (err == OK) { ALOGV("draining decoded buffer %zu, time = %lld us", - frame.index, frame.presentationTimeUs); + frame.index, (long long)frame.presentationTimeUs); ++(state->mNumBuffersDecoded); diff --git a/cmds/stagefright/muxer.cpp b/cmds/stagefright/muxer.cpp index 461b56c..0029aec 100644 --- a/cmds/stagefright/muxer.cpp +++ b/cmds/stagefright/muxer.cpp @@ -53,7 +53,6 @@ static void usage(const char *me) { using namespace android; static int muxing( - const android::sp<android::ALooper> &looper, const char *path, bool useAudio, bool useVideo, @@ -137,7 +136,7 @@ static int muxing( } } - ALOGV("selecting track %d", i); + ALOGV("selecting track %zu", i); err = extractor->selectTrack(i); CHECK_EQ(err, (status_t)OK); @@ -308,7 +307,7 @@ int main(int argc, char **argv) { sp<ALooper> looper = new ALooper; looper->start(); - int result = muxing(looper, argv[0], useAudio, useVideo, outputFileName, + int result = muxing(argv[0], useAudio, useVideo, outputFileName, enableTrim, trimStartTimeMs, trimEndTimeMs, rotationDegrees); looper->stop(); diff --git a/cmds/stagefright/record.cpp b/cmds/stagefright/record.cpp index fdc352e..594c933 100644 --- a/cmds/stagefright/record.cpp +++ b/cmds/stagefright/record.cpp @@ -32,13 +32,13 @@ using namespace android; +static const int32_t kAudioBitRate = 12200; +#if 0 static const int32_t kFramerate = 24; // fps static const int32_t kIFramesIntervalSec = 1; static const int32_t kVideoBitRate = 512 * 1024; -static const int32_t kAudioBitRate = 12200; static const int64_t kDurationUs = 10000000LL; // 10 seconds -#if 0 class DummySource : public MediaSource { public: diff --git a/cmds/stagefright/sf2.cpp b/cmds/stagefright/sf2.cpp index 172dc36..0d64d2f 100644 --- a/cmds/stagefright/sf2.cpp +++ b/cmds/stagefright/sf2.cpp @@ -38,10 +38,10 @@ #include <media/stagefright/MediaExtractor.h> #include <media/stagefright/MediaSource.h> #include <media/stagefright/MetaData.h> -#include <media/stagefright/NativeWindowWrapper.h> #include <media/stagefright/Utils.h> #include <gui/SurfaceComposerClient.h> +#include <gui/Surface.h> #include "include/ESDS.h" @@ -154,8 +154,7 @@ protected: sp<AMessage> format = makeFormat(mSource->getFormat()); if (mSurface != NULL) { - format->setObject( - "native-window", new NativeWindowWrapper(mSurface)); + format->setObject("surface", mSurface); } mCodec->initiateSetup(format); @@ -328,14 +327,14 @@ private: CHECK(size >= 7); CHECK_EQ((unsigned)ptr[0], 1u); // configurationVersion == 1 - uint8_t profile = ptr[1]; - uint8_t level = ptr[3]; + uint8_t profile __unused = ptr[1]; + uint8_t level __unused = ptr[3]; // There is decodable content out there that fails the following // assertion, let's be lenient for now... // CHECK((ptr[4] >> 2) == 0x3f); // reserved - size_t lengthSize = 1 + (ptr[4] & 3); + size_t lengthSize __unused = 1 + (ptr[4] & 3); // commented out check below as H264_QVGA_500_NO_AUDIO.3gp // violates it... @@ -491,7 +490,7 @@ private: if (sizeNeeded > sizeLeft) { if (outBuffer->size() == 0) { - ALOGE("Unable to fit even a single input buffer of size %d.", + ALOGE("Unable to fit even a single input buffer of size %zu.", sizeNeeded); } CHECK_GT(outBuffer->size(), 0u); diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp index 318b56d..a9c6eda 100644 --- a/cmds/stagefright/stagefright.cpp +++ b/cmds/stagefright/stagefright.cpp @@ -965,7 +965,7 @@ int main(int argc, char **argv) { OMXClient client; status_t err = client.connect(); - for (int k = 0; k < argc; ++k) { + for (int k = 0; k < argc && err == OK; ++k) { bool syncInfoPresent = true; const char *filename = argv[k]; diff --git a/cmds/stagefright/stream.cpp b/cmds/stagefright/stream.cpp index 0566d14..1a40e53 100644 --- a/cmds/stagefright/stream.cpp +++ b/cmds/stagefright/stream.cpp @@ -269,7 +269,7 @@ struct MyClient : public BnMediaPlayerClient { : mEOS(false) { } - virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) { + virtual void notify(int msg, int ext1 __unused, int ext2 __unused, const Parcel *obj __unused) { Mutex::Autolock autoLock(mLock); if (msg == MEDIA_ERROR || msg == MEDIA_PLAYBACK_COMPLETE) { @@ -318,7 +318,7 @@ int main(int argc, char **argv) { ssize_t displayWidth = info.w; ssize_t displayHeight = info.h; - ALOGV("display is %d x %d\n", displayWidth, displayHeight); + ALOGV("display is %zd x %zd\n", displayWidth, displayHeight); sp<SurfaceControl> control = composerClient->createSurface( diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp index 3f62ed7..b90da1b 100644 --- a/drm/common/IDrmManagerService.cpp +++ b/drm/common/IDrmManagerService.cpp @@ -34,6 +34,7 @@ #include "IDrmManagerService.h" #define INVALID_BUFFER_LENGTH -1 +#define MAX_BINDER_TRANSACTION_SIZE ((1*1024*1024)-(4096*2)) using namespace android; @@ -933,7 +934,12 @@ status_t BnDrmManagerService::onTransact( //Filling DRM info const int infoType = data.readInt32(); - const int bufferSize = data.readInt32(); + const uint32_t bufferSize = data.readInt32(); + + if (bufferSize > data.dataAvail()) { + return BAD_VALUE; + } + char* buffer = NULL; if (0 < bufferSize) { buffer = (char *)data.readInplace(bufferSize); @@ -986,6 +992,9 @@ status_t BnDrmManagerService::onTransact( const int size = data.readInt32(); for (int index = 0; index < size; ++index) { + if (!data.dataAvail()) { + break; + } const String8 key(data.readString8()); if (key == String8("FileDescriptorKey")) { char buffer[16]; @@ -1035,7 +1044,12 @@ status_t BnDrmManagerService::onTransact( const int uniqueId = data.readInt32(); //Filling DRM Rights - const int bufferSize = data.readInt32(); + const uint32_t bufferSize = data.readInt32(); + if (bufferSize > data.dataAvail()) { + reply->writeInt32(BAD_VALUE); + return DRM_NO_ERROR; + } + const DrmBuffer drmBuffer((char *)data.readInplace(bufferSize), bufferSize); const String8 mimeType(data.readString8()); @@ -1206,10 +1220,13 @@ status_t BnDrmManagerService::onTransact( const int convertId = data.readInt32(); //Filling input data - const int bufferSize = data.readInt32(); + const uint32_t bufferSize = data.readInt32(); + if (bufferSize > data.dataAvail()) { + return BAD_VALUE; + } DrmBuffer* inputData = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize); - DrmConvertedStatus* drmConvertedStatus = convertData(uniqueId, convertId, inputData); + DrmConvertedStatus* drmConvertedStatus = convertData(uniqueId, convertId, inputData); if (NULL != drmConvertedStatus) { //Filling Drm Converted Ststus @@ -1393,7 +1410,12 @@ status_t BnDrmManagerService::onTransact( const int decryptUnitId = data.readInt32(); //Filling Header info - const int bufferSize = data.readInt32(); + const uint32_t bufferSize = data.readInt32(); + if (bufferSize > data.dataAvail()) { + reply->writeInt32(BAD_VALUE); + clearDecryptHandle(&handle); + return DRM_NO_ERROR; + } DrmBuffer* headerInfo = NULL; headerInfo = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize); @@ -1417,9 +1439,17 @@ status_t BnDrmManagerService::onTransact( readDecryptHandleFromParcelData(&handle, data); const int decryptUnitId = data.readInt32(); - const int decBufferSize = data.readInt32(); + const uint32_t decBufferSize = data.readInt32(); + const uint32_t encBufferSize = data.readInt32(); + + if (encBufferSize > data.dataAvail() || + decBufferSize > MAX_BINDER_TRANSACTION_SIZE) { + reply->writeInt32(BAD_VALUE); + reply->writeInt32(0); + clearDecryptHandle(&handle); + return DRM_NO_ERROR; + } - const int encBufferSize = data.readInt32(); DrmBuffer* encBuffer = new DrmBuffer((char *)data.readInplace(encBufferSize), encBufferSize); @@ -1429,8 +1459,10 @@ status_t BnDrmManagerService::onTransact( DrmBuffer* IV = NULL; if (0 != data.dataAvail()) { - const int ivBufferlength = data.readInt32(); - IV = new DrmBuffer((char *)data.readInplace(ivBufferlength), ivBufferlength); + const uint32_t ivBufferlength = data.readInt32(); + if (ivBufferlength <= data.dataAvail()) { + IV = new DrmBuffer((char *)data.readInplace(ivBufferlength), ivBufferlength); + } } const status_t status @@ -1477,7 +1509,11 @@ status_t BnDrmManagerService::onTransact( DecryptHandle handle; readDecryptHandleFromParcelData(&handle, data); - const int numBytes = data.readInt32(); + const uint32_t numBytes = data.readInt32(); + if (numBytes > MAX_BINDER_TRANSACTION_SIZE) { + reply->writeInt32(BAD_VALUE); + return DRM_NO_ERROR; + } char* buffer = new char[numBytes]; const off64_t offset = data.readInt64(); diff --git a/include/media/AVSyncSettings.h b/include/media/AVSyncSettings.h new file mode 100644 index 0000000..10e3bcc --- /dev/null +++ b/include/media/AVSyncSettings.h @@ -0,0 +1,61 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_AV_SYNC_SETTINGS_H +#define ANDROID_AV_SYNC_SETTINGS_H + +namespace android { + +enum AVSyncSource : unsigned { + // let the system decide the best sync source + AVSYNC_SOURCE_DEFAULT = 0, + // sync to the system clock + AVSYNC_SOURCE_SYSTEM_CLOCK = 1, + // sync to the audio track + AVSYNC_SOURCE_AUDIO = 2, + // sync to the display vsync + AVSYNC_SOURCE_VSYNC = 3, + AVSYNC_SOURCE_MAX, +}; + +enum AVSyncAudioAdjustMode : unsigned { + // let the system decide the best audio adjust mode + AVSYNC_AUDIO_ADJUST_MODE_DEFAULT = 0, + // adjust audio by time stretching + AVSYNC_AUDIO_ADJUST_MODE_STRETCH = 1, + // adjust audio by resampling + AVSYNC_AUDIO_ADJUST_MODE_RESAMPLE = 2, + AVSYNC_AUDIO_ADJUST_MODE_MAX, +}; + +// max tolerance when adjusting playback speed to desired playback speed +#define AVSYNC_TOLERANCE_MAX 1.0f + +struct AVSyncSettings { + AVSyncSource mSource; + AVSyncAudioAdjustMode mAudioAdjustMode; + float mTolerance; + AVSyncSettings() + : mSource(AVSYNC_SOURCE_DEFAULT), + mAudioAdjustMode(AVSYNC_AUDIO_ADJUST_MODE_DEFAULT), + mTolerance(.044f) { } +}; + +} // namespace android + +// --------------------------------------------------------------------------- + +#endif // ANDROID_AV_SYNC_SETTINGS_H diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h index 583695d..61da4f2 100644 --- a/include/media/AudioEffect.h +++ b/include/media/AudioEffect.h @@ -201,8 +201,12 @@ public: */ /* Simple Constructor. + * + * Parameters: + * + * opPackageName: The package name used for app op checks. */ - AudioEffect(); + AudioEffect(const String16& opPackageName); /* Constructor. @@ -211,6 +215,7 @@ public: * * type: type of effect created: can be null if uuid is specified. This corresponds to * the OpenSL ES interface implemented by this effect. + * opPackageName: The package name used for app op checks. * uuid: Uuid of effect created: can be null if type is specified. This uuid corresponds to * a particular implementation of an effect type. * priority: requested priority for effect control: the priority level corresponds to the @@ -227,6 +232,7 @@ public: */ AudioEffect(const effect_uuid_t *type, + const String16& opPackageName, const effect_uuid_t *uuid = NULL, int32_t priority = 0, effect_callback_t cbf = NULL, @@ -239,6 +245,7 @@ public: * Same as above but with type and uuid specified by character strings */ AudioEffect(const char *typeStr, + const String16& opPackageName, const char *uuidStr = NULL, int32_t priority = 0, effect_callback_t cbf = NULL, @@ -406,7 +413,9 @@ protected: void* mUserData; // client context for callback function effect_descriptor_t mDescriptor; // effect descriptor int32_t mId; // system wide unique effect engine instance ID - Mutex mLock; // Mutex for mEnabled access + Mutex mLock; // Mutex for mEnabled access + + String16 mOpPackageName; // The package name used for app op checks. // IEffectClient virtual void controlStatusChanged(bool controlGranted); diff --git a/include/media/AudioPolicy.h b/include/media/AudioPolicy.h index 800b27b..feed402 100644 --- a/include/media/AudioPolicy.h +++ b/include/media/AudioPolicy.h @@ -38,14 +38,17 @@ namespace android { #define MIX_TYPE_PLAYERS 0 #define MIX_TYPE_RECORDERS 1 +// definition of the different events that can be reported on a dynamic policy from +// AudioSystem's implementation of the AudioPolicyClient interface +// keep in sync with AudioSystem.java +#define DYNAMIC_POLICY_EVENT_MIX_STATE_UPDATE 0 + #define MIX_STATE_DISABLED -1 #define MIX_STATE_IDLE 0 #define MIX_STATE_MIXING 1 -#define ROUTE_FLAG_RENDER 0x1 -#define ROUTE_FLAG_LOOP_BACK (0x1 << 1) - -#define MIX_FLAG_NOTIFY_ACTIVITY 0x1 +#define MIX_ROUTE_FLAG_RENDER 0x1 +#define MIX_ROUTE_FLAG_LOOP_BACK (0x1 << 1) #define MAX_MIXES_PER_POLICY 10 #define MAX_CRITERIA_PER_MIX 20 @@ -67,11 +70,15 @@ public: class AudioMix { public: + // flag on an AudioMix indicating the activity on this mix (IDLE, MIXING) + // must be reported through the AudioPolicyClient interface + static const uint32_t kCbFlagNotifyActivity = 0x1; + AudioMix() {} AudioMix(Vector<AttributeMatchCriterion> criteria, uint32_t mixType, audio_config_t format, uint32_t routeFlags, String8 registrationId, uint32_t flags) : mCriteria(criteria), mMixType(mixType), mFormat(format), - mRouteFlags(routeFlags), mRegistrationId(registrationId), mFlags(flags){} + mRouteFlags(routeFlags), mRegistrationId(registrationId), mCbFlags(flags){} status_t readFromParcel(Parcel *parcel); status_t writeToParcel(Parcel *parcel) const; @@ -81,7 +88,7 @@ public: audio_config_t mFormat; uint32_t mRouteFlags; String8 mRegistrationId; - uint32_t mFlags; + uint32_t mCbFlags; // flags indicating which callbacks to use, see kCbFlag* }; }; // namespace android diff --git a/include/media/AudioRecord.h b/include/media/AudioRecord.h index c24a28d..b743c11 100644 --- a/include/media/AudioRecord.h +++ b/include/media/AudioRecord.h @@ -129,8 +129,12 @@ public: /* Constructs an uninitialized AudioRecord. No connection with * AudioFlinger takes place. Use set() after this. + * + * Parameters: + * + * opPackageName: The package name used for app ops. */ - AudioRecord(); + AudioRecord(const String16& opPackageName); /* Creates an AudioRecord object and registers it with AudioFlinger. * Once created, the track needs to be started before it can be used. @@ -143,6 +147,7 @@ public: * format: Audio format (e.g AUDIO_FORMAT_PCM_16_BIT for signed * 16 bits per sample). * channelMask: Channel mask, such that audio_is_input_channel(channelMask) is true. + * opPackageName: The package name used for app ops. * frameCount: Minimum size of track PCM buffer in frames. This defines the * application's contribution to the * latency of the track. The actual size selected by the AudioRecord could @@ -165,6 +170,7 @@ public: uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, + const String16& opPackageName, size_t frameCount = 0, callback_t cbf = NULL, void* user = NULL, @@ -483,7 +489,7 @@ private: // caller must hold lock on mLock for all _l methods - status_t openRecord_l(size_t epoch); + status_t openRecord_l(size_t epoch, const String16& opPackageName); // FIXME enum is faster than strcmp() for parameter 'from' status_t restoreRecord_l(const char *from); @@ -520,6 +526,8 @@ private: status_t mStatus; + String16 mOpPackageName; // The package name used for app ops. + size_t mFrameCount; // corresponds to current IAudioRecord, value is // reported back by AudioFlinger to the client size_t mReqFrameCount; // frame count to request the first or next time diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h index 8d3396d..0cbcdb1 100644 --- a/include/media/AudioSystem.h +++ b/include/media/AudioSystem.h @@ -30,6 +30,7 @@ namespace android { typedef void (*audio_error_callback)(status_t err); +typedef void (*dynamic_policy_callback)(int event, String8 regId, int val); class IAudioFlinger; class IAudioPolicyService; @@ -90,6 +91,7 @@ public: static String8 getParameters(const String8& keys); static void setErrorCallback(audio_error_callback cb); + static void setDynPolicyCallback(dynamic_policy_callback cb); // helper function to obtain AudioFlinger service handle static const sp<IAudioFlinger> get_audio_flinger(); @@ -198,6 +200,7 @@ public: audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate = 0, audio_format_t format = AUDIO_FORMAT_DEFAULT, audio_channel_mask_t channelMask = AUDIO_CHANNEL_OUT_STEREO, @@ -219,6 +222,7 @@ public: static status_t getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -398,6 +402,7 @@ private: static Mutex gLockAPS; // protects gAudioPolicyService and gAudioPolicyServiceClient static sp<IAudioFlinger> gAudioFlinger; static audio_error_callback gAudioErrorCallback; + static dynamic_policy_callback gDynPolicyCallback; static size_t gInBuffSize; // previous parameters for recording buffer size queries diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index e7ee0ce..51d40bb 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -360,6 +360,11 @@ public: /* Return current source sample rate in Hz */ uint32_t getSampleRate() const; + /* Return the original source sample rate in Hz. This corresponds to the sample rate + * if playback rate had normal speed and pitch. + */ + uint32_t getOriginalSampleRate() const; + /* Set source playback rate for timestretch * 1.0 is normal speed: < 1.0 is slower, > 1.0 is faster * 1.0 is normal pitch: < 1.0 is lower pitch, > 1.0 is higher pitch @@ -749,6 +754,7 @@ protected: float mVolume[2]; float mSendLevel; mutable uint32_t mSampleRate; // mutable because getSampleRate() can update it + uint32_t mOriginalSampleRate; AudioPlaybackRate mPlaybackRate; size_t mFrameCount; // corresponds to current IAudioTrack, value is // reported back by AudioFlinger to the client @@ -832,6 +838,9 @@ protected: int64_t mStartUs; // the start time after flush or stop. // only used for offloaded and direct tracks. + bool mPreviousTimestampValid;// true if mPreviousTimestamp is valid + AudioTimestamp mPreviousTimestamp; // used to detect retrograde motion + audio_output_flags_t mFlags; // const after set(), except for bits AUDIO_OUTPUT_FLAG_FAST and AUDIO_OUTPUT_FLAG_OFFLOAD. // mLock must be held to read or write those bits reliably. diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index f927a80..046345c 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -85,6 +85,7 @@ public: uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, + const String16& callingPackage, size_t *pFrameCount, track_flags_t *flags, pid_t tid, // -1 means unused, otherwise must be valid non-0 @@ -198,6 +199,7 @@ public: // AudioFlinger doesn't take over handle reference from client audio_io_handle_t output, int sessionId, + const String16& callingPackage, status_t *status, int *id, int *enabled) = 0; diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h index 56a1dc6..ee462a0 100644 --- a/include/media/IAudioPolicyService.h +++ b/include/media/IAudioPolicyService.h @@ -62,6 +62,7 @@ public: audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate = 0, audio_format_t format = AUDIO_FORMAT_DEFAULT, audio_channel_mask_t channelMask = 0, @@ -80,6 +81,7 @@ public: virtual status_t getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h index df6130d..0fd8933 100644 --- a/include/media/IMediaPlayer.h +++ b/include/media/IMediaPlayer.h @@ -35,6 +35,8 @@ class IDataSource; struct IStreamSource; class IGraphicBufferProducer; struct IMediaHTTPService; +struct AudioPlaybackRate; +struct AVSyncSettings; class IMediaPlayer: public IInterface { @@ -58,7 +60,11 @@ public: virtual status_t stop() = 0; virtual status_t pause() = 0; virtual status_t isPlaying(bool* state) = 0; - virtual status_t setPlaybackRate(float rate) = 0; + virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) = 0; + virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) = 0; + virtual status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) = 0; + virtual status_t getSyncSettings(AVSyncSettings* sync /* nonnull */, + float* videoFps /* nonnull */) = 0; virtual status_t seekTo(int msec) = 0; virtual status_t getCurrentPosition(int* msec) = 0; virtual status_t getDuration(int* msec) = 0; diff --git a/include/media/IMediaPlayerService.h b/include/media/IMediaPlayerService.h index 49a3d61..a316ce2 100644 --- a/include/media/IMediaPlayerService.h +++ b/include/media/IMediaPlayerService.h @@ -47,7 +47,7 @@ class IMediaPlayerService: public IInterface public: DECLARE_META_INTERFACE(MediaPlayerService); - virtual sp<IMediaRecorder> createMediaRecorder() = 0; + virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) = 0; virtual sp<IMediaMetadataRetriever> createMetadataRetriever() = 0; virtual sp<IMediaPlayer> create(const sp<IMediaPlayerClient>& client, int audioSessionId = 0) = 0; @@ -65,8 +65,8 @@ public: // display client when display connection, disconnection or errors occur. // The assumption is that at most one remote display will be connected to the // provided interface at a time. - virtual sp<IRemoteDisplay> listenForRemoteDisplay(const sp<IRemoteDisplayClient>& client, - const String8& iface) = 0; + virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName, + const sp<IRemoteDisplayClient>& client, const String8& iface) = 0; // codecs and audio devices usage tracking for the battery app enum BatteryDataBits { diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h index 824762a..fa917f9 100644 --- a/include/media/MediaPlayerInterface.h +++ b/include/media/MediaPlayerInterface.h @@ -26,8 +26,10 @@ #include <utils/RefBase.h> #include <media/mediaplayer.h> +#include <media/AudioResamplerPublic.h> #include <media/AudioSystem.h> #include <media/AudioTimestamp.h> +#include <media/AVSyncSettings.h> #include <media/Metadata.h> // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is @@ -132,7 +134,8 @@ public: virtual void pause() = 0; virtual void close() = 0; - virtual status_t setPlaybackRatePermille(int32_t /* rate */) { return INVALID_OPERATION;} + virtual status_t setPlaybackRate(const AudioPlaybackRate& rate) = 0; + virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */) = 0; virtual bool needsTrailingPadding() { return true; } virtual status_t setParameters(const String8& /* keyValuePairs */) { return NO_ERROR; } @@ -173,7 +176,31 @@ public: virtual status_t stop() = 0; virtual status_t pause() = 0; virtual bool isPlaying() = 0; - virtual status_t setPlaybackRate(float /* rate */) { return INVALID_OPERATION; } + virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate) { + // by default, players only support setting rate to the default + if (!isAudioPlaybackRateEqual(rate, AUDIO_PLAYBACK_RATE_DEFAULT)) { + return BAD_VALUE; + } + return OK; + } + virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) { + *rate = AUDIO_PLAYBACK_RATE_DEFAULT; + return OK; + } + virtual status_t setSyncSettings(const AVSyncSettings& sync, float /* videoFps */) { + // By default, players only support setting sync source to default; all other sync + // settings are ignored. There is no requirement for getters to return set values. + if (sync.mSource != AVSYNC_SOURCE_DEFAULT) { + return BAD_VALUE; + } + return OK; + } + virtual status_t getSyncSettings( + AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) { + *sync = AVSyncSettings(); + *videoFps = -1.f; + return OK; + } virtual status_t seekTo(int msec) = 0; virtual status_t getCurrentPosition(int *msec) = 0; virtual status_t getDuration(int *msec) = 0; diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h index f55063e..f9feede 100644 --- a/include/media/MediaRecorderBase.h +++ b/include/media/MediaRecorderBase.h @@ -29,7 +29,8 @@ class Surface; class IGraphicBufferProducer; struct MediaRecorderBase { - MediaRecorderBase() {} + MediaRecorderBase(const String16 &opPackageName) + : mOpPackageName(opPackageName) {} virtual ~MediaRecorderBase() {} virtual status_t init() = 0; @@ -57,6 +58,10 @@ struct MediaRecorderBase { virtual status_t dump(int fd, const Vector<String16>& args) const = 0; virtual sp<IGraphicBufferProducer> querySurfaceMediaSource() const = 0; + +protected: + String16 mOpPackageName; + private: MediaRecorderBase(const MediaRecorderBase &); MediaRecorderBase &operator=(const MediaRecorderBase &); diff --git a/include/media/Visualizer.h b/include/media/Visualizer.h index 6167dd6..b92f816 100644 --- a/include/media/Visualizer.h +++ b/include/media/Visualizer.h @@ -65,7 +65,8 @@ public: /* Constructor. * See AudioEffect constructor for details on parameters. */ - Visualizer(int32_t priority = 0, + Visualizer(const String16& opPackageName, + int32_t priority = 0, effect_callback_t cbf = NULL, void* user = NULL, int sessionId = 0); diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h index 256fa9a..3fe749c 100644 --- a/include/media/mediaplayer.h +++ b/include/media/mediaplayer.h @@ -20,6 +20,8 @@ #include <arpa/inet.h> #include <binder/IMemory.h> + +#include <media/AudioResamplerPublic.h> #include <media/IMediaPlayerClient.h> #include <media/IMediaPlayer.h> #include <media/IMediaDeathNotifier.h> @@ -32,8 +34,9 @@ class ANativeWindow; namespace android { -class Surface; +struct AVSyncSettings; class IGraphicBufferProducer; +class Surface; enum media_event_type { MEDIA_NOP = 0, // interface test message @@ -223,7 +226,12 @@ public: status_t stop(); status_t pause(); bool isPlaying(); - status_t setPlaybackRate(float rate); + status_t setPlaybackSettings(const AudioPlaybackRate& rate); + status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */); + status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint); + status_t getSyncSettings( + AVSyncSettings* sync /* nonnull */, + float* videoFps /* nonnull */); status_t getVideoWidth(int *w); status_t getVideoHeight(int *h); status_t seekTo(int msec); @@ -278,7 +286,6 @@ private: int mVideoWidth; int mVideoHeight; int mAudioSessionId; - float mPlaybackRate; float mSendLevel; struct sockaddr_in mRetransmitEndpoint; bool mRetransmitEndpointValid; diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h index 74a6469..8e40c5d 100644 --- a/include/media/mediarecorder.h +++ b/include/media/mediarecorder.h @@ -209,7 +209,7 @@ class MediaRecorder : public BnMediaRecorderClient, public virtual IMediaDeathNotifier { public: - MediaRecorder(); + MediaRecorder(const String16& opPackageName); ~MediaRecorder(); void died(); diff --git a/include/media/stagefright/AudioPlayer.h b/include/media/stagefright/AudioPlayer.h index 98c4fa7..e0cd965 100644 --- a/include/media/stagefright/AudioPlayer.h +++ b/include/media/stagefright/AudioPlayer.h @@ -25,9 +25,10 @@ namespace android { -class MediaSource; +struct AudioPlaybackRate; class AudioTrack; struct AwesomePlayer; +class MediaSource; class AudioPlayer : public TimeSource { public: @@ -73,7 +74,8 @@ public: bool isSeeking(); bool reachedEOS(status_t *finalStatus); - status_t setPlaybackRatePermille(int32_t ratePermille); + status_t setPlaybackRate(const AudioPlaybackRate &rate); + status_t getPlaybackRate(AudioPlaybackRate *rate /* nonnull */); void notifyAudioEOS(); diff --git a/include/media/stagefright/AudioSource.h b/include/media/stagefright/AudioSource.h index 4c9aaad..50cf371 100644 --- a/include/media/stagefright/AudioSource.h +++ b/include/media/stagefright/AudioSource.h @@ -35,6 +35,7 @@ struct AudioSource : public MediaSource, public MediaBufferObserver { // _not_ a bitmask of audio_channels_t constants. AudioSource( audio_source_t inputSource, + const String16 &opPackageName, uint32_t sampleRate, uint32_t channels = 1); diff --git a/include/media/stagefright/MediaSync.h b/include/media/stagefright/MediaSync.h index 8ad74a4..a349986 100644 --- a/include/media/stagefright/MediaSync.h +++ b/include/media/stagefright/MediaSync.h @@ -20,9 +20,12 @@ #include <gui/IConsumerListener.h> #include <gui/IProducerListener.h> +#include <media/AudioResamplerPublic.h> +#include <media/AVSyncSettings.h> #include <media/stagefright/foundation/AHandler.h> #include <utils/Condition.h> +#include <utils/KeyedVector.h> #include <utils/Mutex.h> namespace android { @@ -76,10 +79,7 @@ public: // Called when audio track is used as media clock source. It should be // called before updateQueuedAudioData(). - // |nativeSampleRateInHz| is the sample rate of audio data fed into audio - // track. It's the same number used to create AudioTrack. - status_t configureAudioTrack( - const sp<AudioTrack> &audioTrack, uint32_t nativeSampleRateInHz); + status_t configureAudioTrack(const sp<AudioTrack> &audioTrack); // Create a surface for client to render video frames. This is the surface // on which the client should render video frames. Those video frames will @@ -98,21 +98,31 @@ public: // Set the consumer name of the input queue. void setName(const AString &name); - // Set the playback in a desired speed. - // This method can be called any time. - // |rate| is the ratio between desired speed and the normal one, and should - // be non-negative. The meaning of rate values: - // 1.0 -- normal playback - // 0.0 -- stop or pause - // larger than 1.0 -- faster than normal speed - // between 0.0 and 1.0 -- slower than normal speed - status_t setPlaybackRate(float rate); - // Get the media clock used by the MediaSync so that the client can obtain // corresponding media time or real time via // MediaClock::getMediaTime() and MediaClock::getRealTimeFor(). sp<const MediaClock> getMediaClock(); + // Set the video frame rate hint - this is used by the video FrameScheduler + status_t setVideoFrameRateHint(float rate); + + // Get the video frame rate measurement from the FrameScheduler + // returns -1 if there is no measurement + float getVideoFrameRate(); + + // Set the sync settings parameters. + status_t setSyncSettings(const AVSyncSettings &syncSettings); + + // Gets the sync settings parameters. + void getSyncSettings(AVSyncSettings *syncSettings /* nonnull */); + + // Sets the playback rate using playback settings. + // This method can be called any time. + status_t setPlaybackSettings(const AudioPlaybackRate &rate); + + // Gets the playback rate (playback settings parameters). + void getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + // Get the play time for pending audio frames in audio sink. status_t getPlayTimeForPendingAudioFrames(int64_t *outTimeUs); @@ -190,9 +200,19 @@ private: int64_t mNextBufferItemMediaUs; List<BufferItem> mBufferItems; + + // Keep track of buffers received from |mInput|. This is needed because + // it's possible the consumer of |mOutput| could return a different + // GraphicBuffer::handle (e.g., due to passing buffers through IPC), + // and that could cause problem if the producer of |mInput| only + // supports pre-registered buffers. + KeyedVector<uint64_t, sp<GraphicBuffer> > mBuffersFromInput; sp<ALooper> mLooper; float mPlaybackRate; + AudioPlaybackRate mPlaybackSettings; + AVSyncSettings mSyncSettings; + sp<MediaClock> mMediaClock; MediaSync(); @@ -231,6 +251,22 @@ private: // up. This must be called with mMutex locked. void onAbandoned_l(bool isInput); + // Set the playback in a desired speed. + // This method can be called any time. + // |rate| is the ratio between desired speed and the normal one, and should + // be non-negative. The meaning of rate values: + // 1.0 -- normal playback + // 0.0 -- stop or pause + // larger than 1.0 -- faster than normal speed + // between 0.0 and 1.0 -- slower than normal speed + void updatePlaybackRate_l(float rate); + + // apply new sync settings + void resync_l(); + + // apply playback settings only - without resyncing or updating playback rate + status_t setPlaybackSettings_l(const AudioPlaybackRate &rate); + // helper. bool isPlaying() { return mPlaybackRate != 0.0; } diff --git a/include/media/stagefright/NativeWindowWrapper.h b/include/media/stagefright/NativeWindowWrapper.h deleted file mode 100644 index cfeec22..0000000 --- a/include/media/stagefright/NativeWindowWrapper.h +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2011 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 NATIVE_WINDOW_WRAPPER_H_ - -#define NATIVE_WINDOW_WRAPPER_H_ - -#include <gui/Surface.h> - -namespace android { - -// Surface derives from ANativeWindow which derives from multiple -// base classes, in order to carry it in AMessages, we'll temporarily wrap it -// into a NativeWindowWrapper. - -struct NativeWindowWrapper : RefBase { - NativeWindowWrapper( - const sp<Surface> &surfaceTextureClient) : - mSurfaceTextureClient(surfaceTextureClient) { } - - sp<ANativeWindow> getNativeWindow() const { - return mSurfaceTextureClient; - } - - sp<Surface> getSurfaceTextureClient() const { - return mSurfaceTextureClient; - } - -private: - const sp<Surface> mSurfaceTextureClient; - - DISALLOW_EVIL_CONSTRUCTORS(NativeWindowWrapper); -}; - -} // namespace android - -#endif // NATIVE_WINDOW_WRAPPER_H_ diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h index 0ce1603..5e9d7d4 100644 --- a/include/media/stagefright/Utils.h +++ b/include/media/stagefright/Utils.h @@ -76,6 +76,15 @@ struct HLSTime { bool operator <(const HLSTime &t0, const HLSTime &t1); +// read and write various object to/from AMessage + +void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate); +void readFromAMessage(const sp<AMessage> &msg, AudioPlaybackRate *rate /* nonnull */); + +void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint); +void readFromAMessage( + const sp<AMessage> &msg, AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); + } // namespace android #endif // UTILS_H_ diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp index 7d8222f..bbeb854 100644 --- a/media/libmedia/AudioEffect.cpp +++ b/media/libmedia/AudioEffect.cpp @@ -35,13 +35,14 @@ namespace android { // --------------------------------------------------------------------------- -AudioEffect::AudioEffect() - : mStatus(NO_INIT) +AudioEffect::AudioEffect(const String16& opPackageName) + : mStatus(NO_INIT), mOpPackageName(opPackageName) { } AudioEffect::AudioEffect(const effect_uuid_t *type, + const String16& opPackageName, const effect_uuid_t *uuid, int32_t priority, effect_callback_t cbf, @@ -49,12 +50,13 @@ AudioEffect::AudioEffect(const effect_uuid_t *type, int sessionId, audio_io_handle_t io ) - : mStatus(NO_INIT) + : mStatus(NO_INIT), mOpPackageName(opPackageName) { mStatus = set(type, uuid, priority, cbf, user, sessionId, io); } AudioEffect::AudioEffect(const char *typeStr, + const String16& opPackageName, const char *uuidStr, int32_t priority, effect_callback_t cbf, @@ -62,7 +64,7 @@ AudioEffect::AudioEffect(const char *typeStr, int sessionId, audio_io_handle_t io ) - : mStatus(NO_INIT) + : mStatus(NO_INIT), mOpPackageName(opPackageName) { effect_uuid_t type; effect_uuid_t *pType = NULL; @@ -128,7 +130,7 @@ status_t AudioEffect::set(const effect_uuid_t *type, mIEffectClient = new EffectClient(this); iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor, - mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled); + mIEffectClient, priority, io, mSessionId, mOpPackageName, &mStatus, &mId, &enabled); if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) { ALOGE("set(): AudioFlinger could not create effect, status: %d", mStatus); diff --git a/media/libmedia/AudioPolicy.cpp b/media/libmedia/AudioPolicy.cpp index 786eb63..9d07011 100644 --- a/media/libmedia/AudioPolicy.cpp +++ b/media/libmedia/AudioPolicy.cpp @@ -68,7 +68,7 @@ status_t AudioMix::readFromParcel(Parcel *parcel) mFormat.format = (audio_format_t)parcel->readInt32(); mRouteFlags = parcel->readInt32(); mRegistrationId = parcel->readString8(); - mFlags = (uint32_t)parcel->readInt32(); + mCbFlags = (uint32_t)parcel->readInt32(); size_t size = (size_t)parcel->readInt32(); if (size > MAX_CRITERIA_PER_MIX) { size = MAX_CRITERIA_PER_MIX; @@ -90,7 +90,7 @@ status_t AudioMix::writeToParcel(Parcel *parcel) const parcel->writeInt32(mFormat.format); parcel->writeInt32(mRouteFlags); parcel->writeString8(mRegistrationId); - parcel->writeInt32(mFlags); + parcel->writeInt32(mCbFlags); size_t size = mCriteria.size(); if (size > MAX_CRITERIA_PER_MIX) { size = MAX_CRITERIA_PER_MIX; diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 9f5c4c5..23015c0 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -65,8 +65,8 @@ status_t AudioRecord::getMinFrameCount( // --------------------------------------------------------------------------- -AudioRecord::AudioRecord() - : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), +AudioRecord::AudioRecord(const String16 &opPackageName) + : mStatus(NO_INIT), mOpPackageName(opPackageName), mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mSelectedDeviceId(AUDIO_PORT_HANDLE_NONE) { @@ -77,6 +77,7 @@ AudioRecord::AudioRecord( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, + const String16& opPackageName, size_t frameCount, callback_t cbf, void* user, @@ -85,7 +86,9 @@ AudioRecord::AudioRecord( transfer_type transferType, audio_input_flags_t flags, const audio_attributes_t* pAttributes) - : mStatus(NO_INIT), mSessionId(AUDIO_SESSION_ALLOCATE), + : mStatus(NO_INIT), + mOpPackageName(opPackageName), + mSessionId(AUDIO_SESSION_ALLOCATE), mPreviousPriority(ANDROID_PRIORITY_NORMAL), mPreviousSchedulingGroup(SP_DEFAULT), mProxy(NULL), @@ -136,9 +139,9 @@ status_t AudioRecord::set( 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", + "notificationFrames %u, sessionId %d, transferType %d, flags %#x, opPackageName %s", inputSource, sampleRate, format, channelMask, frameCount, notificationFrames, - sessionId, transferType, flags); + sessionId, transferType, flags, String8(mOpPackageName).string()); switch (transferType) { case TRANSFER_DEFAULT: @@ -235,7 +238,7 @@ status_t AudioRecord::set( } // create the IAudioRecord - status_t status = openRecord_l(0 /*epoch*/); + status_t status = openRecord_l(0 /*epoch*/, mOpPackageName); if (status != NO_ERROR) { if (mAudioRecordThread != 0) { @@ -435,7 +438,7 @@ audio_port_handle_t AudioRecord::getInputDevice() { // ------------------------------------------------------------------------- // must be called with mLock held -status_t AudioRecord::openRecord_l(size_t epoch) +status_t AudioRecord::openRecord_l(size_t epoch, const String16& opPackageName) { const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); if (audioFlinger == 0) { @@ -478,6 +481,7 @@ status_t AudioRecord::openRecord_l(size_t epoch) audio_io_handle_t input; status_t status = AudioSystem::getInputForAttr(&mAttributes, &input, (audio_session_t)mSessionId, + IPCThreadState::self()->getCallingUid(), mSampleRate, mFormat, mChannelMask, mFlags, mSelectedDeviceId); @@ -502,8 +506,10 @@ status_t AudioRecord::openRecord_l(size_t epoch) sp<IMemory> iMem; // for cblk sp<IMemory> bufferMem; sp<IAudioRecord> record = audioFlinger->openRecord(input, - mSampleRate, mFormat, + mSampleRate, + mFormat, mChannelMask, + opPackageName, &temp, &trackFlags, tid, @@ -1032,7 +1038,7 @@ status_t AudioRecord::restoreRecord_l(const char *from) // It will also delete the strong references on previous IAudioRecord and IMemory size_t position = mProxy->getPosition(); mNewPosition = position + mUpdatePeriod; - status_t result = openRecord_l(position); + status_t result = openRecord_l(position, mOpPackageName); if (result == NO_ERROR) { if (mActive) { // callback thread or sync event hasn't changed diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp index 01e6d71..85ed2b1 100644 --- a/media/libmedia/AudioSystem.cpp +++ b/media/libmedia/AudioSystem.cpp @@ -36,6 +36,7 @@ Mutex AudioSystem::gLockAPS; sp<IAudioFlinger> AudioSystem::gAudioFlinger; sp<AudioSystem::AudioFlingerClient> AudioSystem::gAudioFlingerClient; audio_error_callback AudioSystem::gAudioErrorCallback = NULL; +dynamic_policy_callback AudioSystem::gDynPolicyCallback = NULL; // establish binder interface to AudioFlinger service @@ -531,12 +532,18 @@ sp<AudioIoDescriptor> AudioSystem::AudioFlingerClient::getIoDescriptor(audio_io_ return desc; } -void AudioSystem::setErrorCallback(audio_error_callback cb) +/*static*/ void AudioSystem::setErrorCallback(audio_error_callback cb) { Mutex::Autolock _l(gLock); gAudioErrorCallback = cb; } +/*static*/ void AudioSystem::setDynPolicyCallback(dynamic_policy_callback cb) +{ + Mutex::Autolock _l(gLock); + gDynPolicyCallback = cb; +} + // client singleton for AudioPolicyService binder interface // protected by gLockAPS sp<IAudioPolicyService> AudioSystem::gAudioPolicyService; @@ -648,6 +655,7 @@ status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr, audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -657,7 +665,7 @@ status_t AudioSystem::getOutputForAttr(const audio_attributes_t *attr, { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return NO_INIT; - return aps->getOutputForAttr(attr, output, session, stream, + return aps->getOutputForAttr(attr, output, session, stream, uid, samplingRate, format, channelMask, flags, selectedDeviceId, offloadInfo); } @@ -692,6 +700,7 @@ void AudioSystem::releaseOutput(audio_io_handle_t output, status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -701,7 +710,7 @@ status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr, const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); if (aps == 0) return NO_INIT; return aps->getInputForAttr( - attr, input, session, samplingRate, format, channelMask, flags, selectedDeviceId); + attr, input, session, uid, samplingRate, format, channelMask, flags, selectedDeviceId); } status_t AudioSystem::startInput(audio_io_handle_t input, @@ -937,6 +946,7 @@ status_t AudioSystem::addAudioPortCallback(const sp<AudioPortCallback>& callBack return gAudioPolicyServiceClient->addAudioPortCallback(callBack); } +/*static*/ status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callBack) { const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service(); @@ -949,7 +959,6 @@ status_t AudioSystem::removeAudioPortCallback(const sp<AudioPortCallback>& callB return gAudioPolicyServiceClient->removeAudioPortCallback(callBack); } - status_t AudioSystem::acquireSoundTriggerSession(audio_session_t *session, audio_io_handle_t *ioHandle, audio_devices_t *device) @@ -1047,7 +1056,16 @@ void AudioSystem::AudioPolicyServiceClient::onAudioPatchListUpdate() void AudioSystem::AudioPolicyServiceClient::onDynamicPolicyMixStateUpdate( String8 regId, int32_t state) { - ALOGV("TODO propagate onDynamicPolicyMixStateUpdate(%s, %d)", regId.string(), state); + ALOGV("AudioPolicyServiceClient::onDynamicPolicyMixStateUpdate(%s, %d)", regId.string(), state); + dynamic_policy_callback cb = NULL; + { + Mutex::Autolock _l(AudioSystem::gLock); + cb = gDynPolicyCallback; + } + + if (cb != NULL) { + cb(DYNAMIC_POLICY_EVENT_MIX_STATE_UPDATE, regId, state); + } } void AudioSystem::AudioPolicyServiceClient::binderDied(const wp<IBinder>& who __unused) diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 8555983..76d9169 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -393,6 +393,7 @@ status_t AudioTrack::set( return BAD_VALUE; } mSampleRate = sampleRate; + mOriginalSampleRate = sampleRate; mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; // Make copy of input parameter offloadInfo so that in the future: @@ -470,6 +471,7 @@ status_t AudioTrack::set( mSequence = 1; mObservedSequence = mSequence; mInUnderrun = false; + mPreviousTimestampValid = false; return NO_ERROR; } @@ -496,6 +498,8 @@ status_t AudioTrack::start() if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) { // reset current position as seen by client to 0 mPosition = 0; + mPreviousTimestampValid = false; + // For offloaded tracks, we don't know if the hardware counters are really zero here, // since the flush is asynchronous and stop may not fully drain. // We save the time when the track is started to later verify whether @@ -756,6 +760,15 @@ uint32_t AudioTrack::getSampleRate() const return mSampleRate; } +uint32_t AudioTrack::getOriginalSampleRate() const +{ + if (mIsTimed) { + return 0; + } + + return mOriginalSampleRate; +} + status_t AudioTrack::setPlaybackRate(const AudioPlaybackRate &playbackRate) { AutoMutex lock(mLock); @@ -995,6 +1008,7 @@ status_t AudioTrack::reload() mNewPosition = mUpdatePeriod; (void) updateAndGetPosition_l(); mPosition = 0; + mPreviousTimestampValid = false; #if 0 // The documentation is not clear on the behavior of reload() and the restoration // of loop count. Historically we have not restored loop count, start, end, @@ -1063,7 +1077,7 @@ status_t AudioTrack::createTrack_l() status_t status; status = AudioSystem::getOutputForAttr(attr, &output, - (audio_session_t)mSessionId, &streamType, + (audio_session_t)mSessionId, &streamType, mClientUid, mSampleRate, mFormat, mChannelMask, mFlags, mSelectedDeviceId, mOffloadInfo); @@ -1102,6 +1116,7 @@ status_t AudioTrack::createTrack_l() } if (mSampleRate == 0) { mSampleRate = afSampleRate; + mOriginalSampleRate = afSampleRate; } // Client decides whether the track is TIMED (see below), but can only express a preference // for FAST. Server will perform additional tests. @@ -2089,6 +2104,11 @@ status_t AudioTrack::setParameters(const String8& keyValuePairs) status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) { AutoMutex lock(mLock); + + bool previousTimestampValid = mPreviousTimestampValid; + // Set false here to cover all the error return cases. + mPreviousTimestampValid = false; + // FIXME not implemented for fast tracks; should use proxy and SSQ if (mFlags & AUDIO_OUTPUT_FLAG_FAST) { return INVALID_OPERATION; @@ -2187,6 +2207,39 @@ status_t AudioTrack::getTimestamp(AudioTimestamp& timestamp) // IAudioTrack. And timestamp.mPosition is initially in server's // point of view, so we need to apply the same fudge factor to it. } + + // Prevent retrograde motion in timestamp. + // This is sometimes caused by erratic reports of the available space in the ALSA drivers. + if (status == NO_ERROR) { + if (previousTimestampValid) { +#define TIME_TO_NANOS(time) ((uint64_t)time.tv_sec * 1000000000 + time.tv_nsec) + const uint64_t previousTimeNanos = TIME_TO_NANOS(mPreviousTimestamp.mTime); + const uint64_t currentTimeNanos = TIME_TO_NANOS(timestamp.mTime); +#undef TIME_TO_NANOS + if (currentTimeNanos < previousTimeNanos) { + ALOGW("retrograde timestamp time"); + // FIXME Consider blocking this from propagating upwards. + } + + // Looking at signed delta will work even when the timestamps + // are wrapping around. + int32_t deltaPosition = static_cast<int32_t>(timestamp.mPosition + - mPreviousTimestamp.mPosition); + // position can bobble slightly as an artifact; this hides the bobble + static const int32_t MINIMUM_POSITION_DELTA = 8; + ALOGW_IF(deltaPosition < 0, + "retrograde timestamp position corrected, %d = %u - %u", + deltaPosition, + timestamp.mPosition, + mPreviousTimestamp.mPosition); + if (deltaPosition < MINIMUM_POSITION_DELTA) { + timestamp = mPreviousTimestamp; // Use last valid timestamp. + } + } + mPreviousTimestamp = timestamp; + mPreviousTimestampValid = true; + } + return status; } diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 38055f9..d48532e 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -174,6 +174,7 @@ public: uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, + const String16& opPackageName, size_t *pFrameCount, track_flags_t *flags, pid_t tid, @@ -190,6 +191,7 @@ public: data.writeInt32(sampleRate); data.writeInt32(format); data.writeInt32(channelMask); + data.writeString16(opPackageName); size_t frameCount = pFrameCount != NULL ? *pFrameCount : 0; data.writeInt64(frameCount); track_flags_t lFlags = flags != NULL ? *flags : (track_flags_t) TRACK_DEFAULT; @@ -702,6 +704,7 @@ public: int32_t priority, audio_io_handle_t output, int sessionId, + const String16& opPackageName, status_t *status, int *id, int *enabled) @@ -722,6 +725,7 @@ public: data.writeInt32(priority); data.writeInt32((int32_t) output); data.writeInt32(sessionId); + data.writeString16(opPackageName); status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply); if (lStatus != NO_ERROR) { @@ -950,6 +954,7 @@ status_t BnAudioFlinger::onTransact( uint32_t sampleRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); + const String16& opPackageName = data.readString16(); size_t frameCount = data.readInt64(); track_flags_t flags = (track_flags_t) data.readInt32(); pid_t tid = (pid_t) data.readInt32(); @@ -959,9 +964,8 @@ status_t BnAudioFlinger::onTransact( sp<IMemory> buffers; status_t status; sp<IAudioRecord> record = openRecord(input, - sampleRate, format, channelMask, &frameCount, &flags, tid, &sessionId, - ¬ificationFrames, - cblk, buffers, &status); + sampleRate, format, channelMask, opPackageName, &frameCount, &flags, tid, + &sessionId, ¬ificationFrames, cblk, buffers, &status); LOG_ALWAYS_FATAL_IF((record != 0) != (status == NO_ERROR)); reply->writeInt64(frameCount); reply->writeInt32(flags); @@ -1247,12 +1251,13 @@ status_t BnAudioFlinger::onTransact( int32_t priority = data.readInt32(); audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); int sessionId = data.readInt32(); + const String16 opPackageName = data.readString16(); status_t status; int id; int enabled; sp<IEffect> effect = createEffect(&desc, client, priority, output, sessionId, - &status, &id, &enabled); + opPackageName, &status, &id, &enabled); reply->writeInt32(status); reply->writeInt32(id); reply->writeInt32(enabled); diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp index fc36a7f..fd18f17 100644 --- a/media/libmedia/IAudioPolicyService.cpp +++ b/media/libmedia/IAudioPolicyService.cpp @@ -171,6 +171,7 @@ public: audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -207,6 +208,7 @@ public: data.writeInt32(1); data.writeInt32(*stream); } + data.writeInt32(uid); data.writeInt32(samplingRate); data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channelMask); @@ -275,6 +277,7 @@ public: virtual status_t getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -293,6 +296,7 @@ public: } data.write(attr, sizeof(audio_attributes_t)); data.writeInt32(session); + data.writeInt32(uid); data.writeInt32(samplingRate); data.writeInt32(static_cast <uint32_t>(format)); data.writeInt32(channelMask); @@ -852,6 +856,7 @@ status_t BnAudioPolicyService::onTransact( if (hasStream) { stream = (audio_stream_type_t)data.readInt32(); } + uid_t uid = (uid_t)data.readInt32(); uint32_t samplingRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); @@ -865,7 +870,7 @@ status_t BnAudioPolicyService::onTransact( } audio_io_handle_t output; status_t status = getOutputForAttr(hasAttributes ? &attr : NULL, - &output, session, &stream, + &output, session, &stream, uid, samplingRate, format, channelMask, flags, selectedDeviceId, hasOffloadInfo ? &offloadInfo : NULL); reply->writeInt32(status); @@ -912,13 +917,14 @@ status_t BnAudioPolicyService::onTransact( audio_attributes_t attr; data.read(&attr, sizeof(audio_attributes_t)); audio_session_t session = (audio_session_t)data.readInt32(); + uid_t uid = (uid_t)data.readInt32(); uint32_t samplingRate = data.readInt32(); audio_format_t format = (audio_format_t) data.readInt32(); audio_channel_mask_t channelMask = data.readInt32(); audio_input_flags_t flags = (audio_input_flags_t) data.readInt32(); audio_port_handle_t selectedDeviceId = (audio_port_handle_t) data.readInt32(); audio_io_handle_t input; - status_t status = getInputForAttr(&attr, &input, session, + status_t status = getInputForAttr(&attr, &input, session, uid, samplingRate, format, channelMask, flags, selectedDeviceId); reply->writeInt32(status); diff --git a/media/libmedia/IHDCP.cpp b/media/libmedia/IHDCP.cpp index 79944ee..f3a8902 100644 --- a/media/libmedia/IHDCP.cpp +++ b/media/libmedia/IHDCP.cpp @@ -284,11 +284,17 @@ status_t BnHDCP::onTransact( size_t offset = data.readInt32(); size_t size = data.readInt32(); uint32_t streamCTR = data.readInt32(); - void *outData = malloc(size); + void *outData = NULL; uint64_t inputCTR; - status_t err = encryptNative(graphicBuffer, offset, size, - streamCTR, &inputCTR, outData); + status_t err = ERROR_OUT_OF_RANGE; + + outData = malloc(size); + + if (outData != NULL) { + err = encryptNative(graphicBuffer, offset, size, + streamCTR, &inputCTR, outData); + } reply->writeInt32(err); diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp index 0091078..bde35f2 100644 --- a/media/libmedia/IMediaPlayer.cpp +++ b/media/libmedia/IMediaPlayer.cpp @@ -21,6 +21,9 @@ #include <binder/Parcel.h> +#include <media/AudioResamplerPublic.h> +#include <media/AVSyncSettings.h> + #include <media/IDataSource.h> #include <media/IMediaHTTPService.h> #include <media/IMediaPlayer.h> @@ -41,7 +44,10 @@ enum { START, STOP, IS_PLAYING, - SET_PLAYBACK_RATE, + SET_PLAYBACK_SETTINGS, + GET_PLAYBACK_SETTINGS, + SET_SYNC_SETTINGS, + GET_SYNC_SETTINGS, PAUSE, SEEK_TO, GET_CURRENT_POSITION, @@ -175,15 +181,63 @@ public: return reply.readInt32(); } - status_t setPlaybackRate(float rate) + status_t setPlaybackSettings(const AudioPlaybackRate& rate) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + data.writeFloat(rate.mSpeed); + data.writeFloat(rate.mPitch); + data.writeInt32((int32_t)rate.mFallbackMode); + data.writeInt32((int32_t)rate.mStretchMode); + remote()->transact(SET_PLAYBACK_SETTINGS, data, &reply); + return reply.readInt32(); + } + + status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(GET_PLAYBACK_SETTINGS, data, &reply); + status_t err = reply.readInt32(); + if (err == OK) { + *rate = AUDIO_PLAYBACK_RATE_DEFAULT; + rate->mSpeed = reply.readFloat(); + rate->mPitch = reply.readFloat(); + rate->mFallbackMode = (AudioTimestretchFallbackMode)reply.readInt32(); + rate->mStretchMode = (AudioTimestretchStretchMode)reply.readInt32(); + } + return err; + } + + status_t setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); - data.writeFloat(rate); - remote()->transact(SET_PLAYBACK_RATE, data, &reply); + data.writeInt32((int32_t)sync.mSource); + data.writeInt32((int32_t)sync.mAudioAdjustMode); + data.writeFloat(sync.mTolerance); + data.writeFloat(videoFpsHint); + remote()->transact(SET_SYNC_SETTINGS, data, &reply); return reply.readInt32(); } + status_t getSyncSettings(AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) + { + Parcel data, reply; + data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor()); + remote()->transact(GET_SYNC_SETTINGS, data, &reply); + status_t err = reply.readInt32(); + if (err == OK) { + AVSyncSettings settings; + settings.mSource = (AVSyncSource)reply.readInt32(); + settings.mAudioAdjustMode = (AVSyncAudioAdjustMode)reply.readInt32(); + settings.mTolerance = reply.readFloat(); + *sync = settings; + *videoFps = reply.readFloat(); + } + return err; + } + status_t pause() { Parcel data, reply; @@ -453,9 +507,51 @@ status_t BnMediaPlayer::onTransact( reply->writeInt32(ret); return NO_ERROR; } break; - case SET_PLAYBACK_RATE: { + case SET_PLAYBACK_SETTINGS: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; + rate.mSpeed = data.readFloat(); + rate.mPitch = data.readFloat(); + rate.mFallbackMode = (AudioTimestretchFallbackMode)data.readInt32(); + rate.mStretchMode = (AudioTimestretchStretchMode)data.readInt32(); + reply->writeInt32(setPlaybackSettings(rate)); + return NO_ERROR; + } break; + case GET_PLAYBACK_SETTINGS: { CHECK_INTERFACE(IMediaPlayer, data, reply); - reply->writeInt32(setPlaybackRate(data.readFloat())); + AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; + status_t err = getPlaybackSettings(&rate); + reply->writeInt32(err); + if (err == OK) { + reply->writeFloat(rate.mSpeed); + reply->writeFloat(rate.mPitch); + reply->writeInt32((int32_t)rate.mFallbackMode); + reply->writeInt32((int32_t)rate.mStretchMode); + } + return NO_ERROR; + } break; + case SET_SYNC_SETTINGS: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + AVSyncSettings sync; + sync.mSource = (AVSyncSource)data.readInt32(); + sync.mAudioAdjustMode = (AVSyncAudioAdjustMode)data.readInt32(); + sync.mTolerance = data.readFloat(); + float videoFpsHint = data.readFloat(); + reply->writeInt32(setSyncSettings(sync, videoFpsHint)); + return NO_ERROR; + } break; + case GET_SYNC_SETTINGS: { + CHECK_INTERFACE(IMediaPlayer, data, reply); + AVSyncSettings sync; + float videoFps; + status_t err = getSyncSettings(&sync, &videoFps); + reply->writeInt32(err); + if (err == OK) { + reply->writeInt32((int32_t)sync.mSource); + reply->writeInt32((int32_t)sync.mAudioAdjustMode); + reply->writeFloat(sync.mTolerance); + reply->writeFloat(videoFps); + } return NO_ERROR; } break; case PAUSE: { diff --git a/media/libmedia/IMediaPlayerService.cpp b/media/libmedia/IMediaPlayerService.cpp index aa7b2e1..05f8670 100644 --- a/media/libmedia/IMediaPlayerService.cpp +++ b/media/libmedia/IMediaPlayerService.cpp @@ -78,10 +78,11 @@ public: return interface_cast<IMediaPlayer>(reply.readStrongBinder()); } - virtual sp<IMediaRecorder> createMediaRecorder() + virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeString16(opPackageName); remote()->transact(CREATE_MEDIA_RECORDER, data, &reply); return interface_cast<IMediaRecorder>(reply.readStrongBinder()); } @@ -128,11 +129,12 @@ public: return remote()->transact(PULL_BATTERY_DATA, data, reply); } - virtual sp<IRemoteDisplay> listenForRemoteDisplay(const sp<IRemoteDisplayClient>& client, - const String8& iface) + virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName, + const sp<IRemoteDisplayClient>& client, const String8& iface) { Parcel data, reply; data.writeInterfaceToken(IMediaPlayerService::getInterfaceDescriptor()); + data.writeString16(opPackageName); data.writeStrongBinder(IInterface::asBinder(client)); data.writeString8(iface); remote()->transact(LISTEN_FOR_REMOTE_DISPLAY, data, &reply); @@ -166,7 +168,8 @@ status_t BnMediaPlayerService::onTransact( } break; case CREATE_MEDIA_RECORDER: { CHECK_INTERFACE(IMediaPlayerService, data, reply); - sp<IMediaRecorder> recorder = createMediaRecorder(); + const String16 opPackageName = data.readString16(); + sp<IMediaRecorder> recorder = createMediaRecorder(opPackageName); reply->writeStrongBinder(IInterface::asBinder(recorder)); return NO_ERROR; } break; @@ -214,10 +217,11 @@ status_t BnMediaPlayerService::onTransact( } break; case LISTEN_FOR_REMOTE_DISPLAY: { CHECK_INTERFACE(IMediaPlayerService, data, reply); + const String16 opPackageName = data.readString16(); sp<IRemoteDisplayClient> client( interface_cast<IRemoteDisplayClient>(data.readStrongBinder())); String8 iface(data.readString8()); - sp<IRemoteDisplay> display(listenForRemoteDisplay(client, iface)); + sp<IRemoteDisplay> display(listenForRemoteDisplay(opPackageName, client, iface)); reply->writeStrongBinder(IInterface::asBinder(display)); return NO_ERROR; } break; diff --git a/media/libmedia/Visualizer.cpp b/media/libmedia/Visualizer.cpp index 9d69b6a..dc46038 100644 --- a/media/libmedia/Visualizer.cpp +++ b/media/libmedia/Visualizer.cpp @@ -34,11 +34,12 @@ namespace android { // --------------------------------------------------------------------------- -Visualizer::Visualizer (int32_t priority, +Visualizer::Visualizer (const String16& opPackageName, + int32_t priority, effect_callback_t cbf, void* user, int sessionId) - : AudioEffect(SL_IID_VISUALIZATION, NULL, priority, cbf, user, sessionId), + : AudioEffect(SL_IID_VISUALIZATION, opPackageName, NULL, priority, cbf, user, sessionId), mCaptureRate(CAPTURE_RATE_DEF), mCaptureSize(CAPTURE_SIZE_DEF), mSampleRate(44100000), diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp index 9a276ae..81a5e8c 100644 --- a/media/libmedia/mediaplayer.cpp +++ b/media/libmedia/mediaplayer.cpp @@ -32,7 +32,9 @@ #include <gui/Surface.h> #include <media/mediaplayer.h> +#include <media/AudioResamplerPublic.h> #include <media/AudioSystem.h> +#include <media/AVSyncSettings.h> #include <media/IDataSource.h> #include <binder/MemoryBase.h> @@ -60,7 +62,6 @@ MediaPlayer::MediaPlayer() mLoop = false; mLeftVolume = mRightVolume = 1.0; mVideoWidth = mVideoHeight = 0; - mPlaybackRate = 1.0; mLockThreadId = 0; mAudioSessionId = AudioSystem::newAudioUniqueId(); AudioSystem::acquireAudioSessionId(mAudioSessionId, -1); @@ -389,6 +390,9 @@ bool MediaPlayer::isPlaying() if ((mCurrentState & MEDIA_PLAYER_STARTED) && ! temp) { ALOGE("internal/external state mismatch corrected"); mCurrentState = MEDIA_PLAYER_PAUSED; + } else if ((mCurrentState & MEDIA_PLAYER_PAUSED) && temp) { + ALOGE("internal/external state mismatch corrected"); + mCurrentState = MEDIA_PLAYER_STARTED; } return temp; } @@ -396,22 +400,50 @@ bool MediaPlayer::isPlaying() return false; } -status_t MediaPlayer::setPlaybackRate(float rate) +status_t MediaPlayer::setPlaybackSettings(const AudioPlaybackRate& rate) { - ALOGV("setPlaybackRate: %f", rate); - if (rate <= 0.0) { + ALOGV("setPlaybackSettings: %f %f %d %d", + rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); + // Negative speed and pitch does not make sense. Further validation will + // be done by the respective mediaplayers. + if (rate.mSpeed < 0.f || rate.mPitch < 0.f) { return BAD_VALUE; } Mutex::Autolock _l(mLock); - if (mPlayer != 0) { - if (mPlaybackRate == rate) { - return NO_ERROR; + if (mPlayer == 0) return INVALID_OPERATION; + status_t err = mPlayer->setPlaybackSettings(rate); + if (err == OK) { + if (rate.mSpeed == 0.f && mCurrentState == MEDIA_PLAYER_STARTED) { + mCurrentState = MEDIA_PLAYER_PAUSED; + } else if (rate.mSpeed != 0.f && mCurrentState == MEDIA_PLAYER_PAUSED) { + mCurrentState = MEDIA_PLAYER_STARTED; } - mPlaybackRate = rate; - return mPlayer->setPlaybackRate(rate); } - ALOGV("setPlaybackRate: no active player"); - return INVALID_OPERATION; + return err; +} + +status_t MediaPlayer::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) +{ + Mutex::Autolock _l(mLock); + if (mPlayer == 0) return INVALID_OPERATION; + return mPlayer->getPlaybackSettings(rate); +} + +status_t MediaPlayer::setSyncSettings(const AVSyncSettings& sync, float videoFpsHint) +{ + ALOGV("setSyncSettings: %u %u %f %f", + sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint); + Mutex::Autolock _l(mLock); + if (mPlayer == 0) return INVALID_OPERATION; + return mPlayer->setSyncSettings(sync, videoFpsHint); +} + +status_t MediaPlayer::getSyncSettings( + AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) +{ + Mutex::Autolock _l(mLock); + if (mPlayer == 0) return INVALID_OPERATION; + return mPlayer->getSyncSettings(sync, videoFps); } status_t MediaPlayer::getVideoWidth(int *w) diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp index a2d6e53..9470936 100644 --- a/media/libmedia/mediarecorder.cpp +++ b/media/libmedia/mediarecorder.cpp @@ -594,13 +594,13 @@ status_t MediaRecorder::release() return INVALID_OPERATION; } -MediaRecorder::MediaRecorder() : mSurfaceMediaSource(NULL) +MediaRecorder::MediaRecorder(const String16& opPackageName) : mSurfaceMediaSource(NULL) { ALOGV("constructor"); const sp<IMediaPlayerService>& service(getMediaPlayerService()); if (service != NULL) { - mMediaRecorder = service->createMediaRecorder(); + mMediaRecorder = service->createMediaRecorder(opPackageName); } if (mMediaRecorder != NULL) { mCurrentState = MEDIA_RECORDER_IDLE; diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp index 3bc763f..891a9e9 100644 --- a/media/libmediaplayerservice/MediaPlayerService.cpp +++ b/media/libmediaplayerservice/MediaPlayerService.cpp @@ -307,10 +307,10 @@ MediaPlayerService::~MediaPlayerService() ALOGV("MediaPlayerService destroyed"); } -sp<IMediaRecorder> MediaPlayerService::createMediaRecorder() +sp<IMediaRecorder> MediaPlayerService::createMediaRecorder(const String16 &opPackageName) { pid_t pid = IPCThreadState::self()->getCallingPid(); - sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid); + sp<MediaRecorderClient> recorder = new MediaRecorderClient(this, pid, opPackageName); wp<MediaRecorderClient> w = recorder; Mutex::Autolock lock(mLock); mMediaRecorderClients.add(w); @@ -381,12 +381,13 @@ sp<IHDCP> MediaPlayerService::makeHDCP(bool createEncryptionModule) { } sp<IRemoteDisplay> MediaPlayerService::listenForRemoteDisplay( + const String16 &opPackageName, const sp<IRemoteDisplayClient>& client, const String8& iface) { if (!checkPermission("android.permission.CONTROL_WIFI_DISPLAY")) { return NULL; } - return new RemoteDisplay(client, iface.string()); + return new RemoteDisplay(opPackageName, client, iface.string()); } status_t MediaPlayerService::AudioOutput::dump(int fd, const Vector<String16>& args) const @@ -980,12 +981,52 @@ status_t MediaPlayerService::Client::isPlaying(bool* state) return NO_ERROR; } -status_t MediaPlayerService::Client::setPlaybackRate(float rate) +status_t MediaPlayerService::Client::setPlaybackSettings(const AudioPlaybackRate& rate) { - ALOGV("[%d] setPlaybackRate(%f)", mConnId, rate); + ALOGV("[%d] setPlaybackSettings(%f, %f, %d, %d)", + mConnId, rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); sp<MediaPlayerBase> p = getPlayer(); if (p == 0) return UNKNOWN_ERROR; - return p->setPlaybackRate(rate); + return p->setPlaybackSettings(rate); +} + +status_t MediaPlayerService::Client::getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */) +{ + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->getPlaybackSettings(rate); + if (ret == NO_ERROR) { + ALOGV("[%d] getPlaybackSettings(%f, %f, %d, %d)", + mConnId, rate->mSpeed, rate->mPitch, rate->mFallbackMode, rate->mStretchMode); + } else { + ALOGV("[%d] getPlaybackSettings returned %d", mConnId, ret); + } + return ret; +} + +status_t MediaPlayerService::Client::setSyncSettings( + const AVSyncSettings& sync, float videoFpsHint) +{ + ALOGV("[%d] setSyncSettings(%u, %u, %f, %f)", + mConnId, sync.mSource, sync.mAudioAdjustMode, sync.mTolerance, videoFpsHint); + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + return p->setSyncSettings(sync, videoFpsHint); +} + +status_t MediaPlayerService::Client::getSyncSettings( + AVSyncSettings* sync /* nonnull */, float* videoFps /* nonnull */) +{ + sp<MediaPlayerBase> p = getPlayer(); + if (p == 0) return UNKNOWN_ERROR; + status_t ret = p->getSyncSettings(sync, videoFps); + if (ret == NO_ERROR) { + ALOGV("[%d] getSyncSettings(%u, %u, %f, %f)", + mConnId, sync->mSource, sync->mAudioAdjustMode, sync->mTolerance, *videoFps); + } else { + ALOGV("[%d] getSyncSettings returned %d", mConnId, ret); + } + return ret; } status_t MediaPlayerService::Client::getCurrentPosition(int *msec) @@ -1310,7 +1351,7 @@ MediaPlayerService::AudioOutput::AudioOutput(int sessionId, int uid, int pid, mStreamType = AUDIO_STREAM_MUSIC; mLeftVolume = 1.0; mRightVolume = 1.0; - mPlaybackRatePermille = 1000; + mPlaybackRate = AUDIO_PLAYBACK_RATE_DEFAULT; mSampleRateHz = 0; mMsecsPerFrame = 0; mAuxEffectId = 0; @@ -1633,7 +1674,7 @@ status_t MediaPlayerService::AudioOutput::open( mSampleRateHz = sampleRate; mFlags = flags; - mMsecsPerFrame = mPlaybackRatePermille / (float) sampleRate; + mMsecsPerFrame = 1E3f / (mPlaybackRate.mSpeed * sampleRate); uint32_t pos; if (t->getPosition(&pos) == OK) { mBytesWritten = uint64_t(pos) * t->frameSize(); @@ -1642,7 +1683,7 @@ status_t MediaPlayerService::AudioOutput::open( status_t res = NO_ERROR; if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0) { - res = t->setSampleRate(mPlaybackRatePermille * mSampleRateHz / 1000); + res = t->setPlaybackRate(mPlaybackRate); if (res == NO_ERROR) { t->setAuxEffectSendLevel(mSendLevel); res = t->attachAuxEffect(mAuxEffectId); @@ -1738,22 +1779,38 @@ void MediaPlayerService::AudioOutput::setVolume(float left, float right) } } -status_t MediaPlayerService::AudioOutput::setPlaybackRatePermille(int32_t ratePermille) +status_t MediaPlayerService::AudioOutput::setPlaybackRate(const AudioPlaybackRate &rate) { - ALOGV("setPlaybackRatePermille(%d)", ratePermille); - status_t res = NO_ERROR; - if (mTrack != 0) { - res = mTrack->setSampleRate(ratePermille * mSampleRateHz / 1000); - } else { - res = NO_INIT; + ALOGV("setPlaybackRate(%f %f %d %d)", + rate.mSpeed, rate.mPitch, rate.mFallbackMode, rate.mStretchMode); + if (mTrack == 0) { + // remember rate so that we can set it when the track is opened + mPlaybackRate = rate; + return OK; + } + status_t res = mTrack->setPlaybackRate(rate); + if (res != NO_ERROR) { + return res; } - mPlaybackRatePermille = ratePermille; + // rate.mSpeed is always greater than 0 if setPlaybackRate succeeded + CHECK_GT(rate.mSpeed, 0.f); + mPlaybackRate = rate; if (mSampleRateHz != 0) { - mMsecsPerFrame = mPlaybackRatePermille / (float) mSampleRateHz; + mMsecsPerFrame = 1E3f / (rate.mSpeed * mSampleRateHz); } return res; } +status_t MediaPlayerService::AudioOutput::getPlaybackRate(AudioPlaybackRate *rate) +{ + ALOGV("setPlaybackRate"); + if (mTrack == 0) { + return NO_INIT; + } + *rate = mTrack->getPlaybackRate(); + return NO_ERROR; +} + status_t MediaPlayerService::AudioOutput::setAuxEffectSendLevel(float level) { ALOGV("setAuxEffectSendLevel(%f)", level); diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h index 6ddfe14..5103841 100644 --- a/media/libmediaplayerservice/MediaPlayerService.h +++ b/media/libmediaplayerservice/MediaPlayerService.h @@ -34,7 +34,9 @@ namespace android { +struct AudioPlaybackRate; class AudioTrack; +struct AVSyncSettings; class IDataSource; class IMediaRecorder; class IMediaMetadataRetriever; @@ -109,7 +111,9 @@ class MediaPlayerService : public BnMediaPlayerService void setAudioAttributes(const audio_attributes_t * attributes); void setVolume(float left, float right); - virtual status_t setPlaybackRatePermille(int32_t ratePermille); + virtual status_t setPlaybackRate(const AudioPlaybackRate& rate); + virtual status_t getPlaybackRate(AudioPlaybackRate* rate /* nonnull */); + status_t setAuxEffectSendLevel(float level); status_t attachAuxEffect(int effectId); virtual status_t dump(int fd, const Vector<String16>& args) const; @@ -139,7 +143,7 @@ class MediaPlayerService : public BnMediaPlayerService const audio_attributes_t *mAttributes; float mLeftVolume; float mRightVolume; - int32_t mPlaybackRatePermille; + AudioPlaybackRate mPlaybackRate; uint32_t mSampleRateHz; // sample rate of the content, as set in open() float mMsecsPerFrame; int mSessionId; @@ -188,7 +192,7 @@ public: static void instantiate(); // IMediaPlayerService interface - virtual sp<IMediaRecorder> createMediaRecorder(); + virtual sp<IMediaRecorder> createMediaRecorder(const String16 &opPackageName); void removeMediaRecorderClient(wp<MediaRecorderClient> client); virtual sp<IMediaMetadataRetriever> createMetadataRetriever(); @@ -200,8 +204,8 @@ public: virtual sp<IDrm> makeDrm(); virtual sp<IHDCP> makeHDCP(bool createEncryptionModule); - virtual sp<IRemoteDisplay> listenForRemoteDisplay(const sp<IRemoteDisplayClient>& client, - const String8& iface); + virtual sp<IRemoteDisplay> listenForRemoteDisplay(const String16 &opPackageName, + const sp<IRemoteDisplayClient>& client, const String8& iface); virtual status_t dump(int fd, const Vector<String16>& args); void removeClient(wp<Client> client); @@ -262,7 +266,11 @@ private: virtual status_t stop(); virtual status_t pause(); virtual status_t isPlaying(bool* state); - virtual status_t setPlaybackRate(float rate); + virtual status_t setPlaybackSettings(const AudioPlaybackRate& rate); + virtual status_t getPlaybackSettings(AudioPlaybackRate* rate /* nonnull */); + virtual status_t setSyncSettings(const AVSyncSettings& rate, float videoFpsHint); + virtual status_t getSyncSettings(AVSyncSettings* rate /* nonnull */, + float* videoFps /* nonnull */); virtual status_t seekTo(int msec); virtual status_t getCurrentPosition(int* msec); virtual status_t getDuration(int* msec); diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp index 319ebb0..40e9d1c 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.cpp +++ b/media/libmediaplayerservice/MediaRecorderClient.cpp @@ -290,11 +290,12 @@ status_t MediaRecorderClient::release() return NO_ERROR; } -MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid) +MediaRecorderClient::MediaRecorderClient(const sp<MediaPlayerService>& service, pid_t pid, + const String16& opPackageName) { ALOGV("Client constructor"); mPid = pid; - mRecorder = new StagefrightRecorder; + mRecorder = new StagefrightRecorder(opPackageName); mMediaPlayerService = service; } diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h index b45344b..e03ec3f 100644 --- a/media/libmediaplayerservice/MediaRecorderClient.h +++ b/media/libmediaplayerservice/MediaRecorderClient.h @@ -62,7 +62,8 @@ private: MediaRecorderClient( const sp<MediaPlayerService>& service, - pid_t pid); + pid_t pid, + const String16& opPackageName); virtual ~MediaRecorderClient(); pid_t mPid; diff --git a/media/libmediaplayerservice/RemoteDisplay.cpp b/media/libmediaplayerservice/RemoteDisplay.cpp index eb959b4..0eb4b5d 100644 --- a/media/libmediaplayerservice/RemoteDisplay.cpp +++ b/media/libmediaplayerservice/RemoteDisplay.cpp @@ -26,13 +26,14 @@ namespace android { RemoteDisplay::RemoteDisplay( + const String16 &opPackageName, const sp<IRemoteDisplayClient> &client, const char *iface) : mLooper(new ALooper), mNetSession(new ANetworkSession) { mLooper->setName("wfd_looper"); - mSource = new WifiDisplaySource(mNetSession, client); + mSource = new WifiDisplaySource(opPackageName, mNetSession, client); mLooper->registerHandler(mSource); mNetSession->start(); diff --git a/media/libmediaplayerservice/RemoteDisplay.h b/media/libmediaplayerservice/RemoteDisplay.h index 1a48981..d4573e9 100644 --- a/media/libmediaplayerservice/RemoteDisplay.h +++ b/media/libmediaplayerservice/RemoteDisplay.h @@ -33,6 +33,7 @@ struct WifiDisplaySource; struct RemoteDisplay : public BnRemoteDisplay { RemoteDisplay( + const String16 &opPackageName, const sp<IRemoteDisplayClient> &client, const char *iface); diff --git a/media/libmediaplayerservice/StagefrightPlayer.cpp b/media/libmediaplayerservice/StagefrightPlayer.cpp index b37aee3..3fedd9b 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.cpp +++ b/media/libmediaplayerservice/StagefrightPlayer.cpp @@ -188,6 +188,14 @@ status_t StagefrightPlayer::getParameter(int key, Parcel *reply) { return mPlayer->getParameter(key, reply); } +status_t StagefrightPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) { + return mPlayer->setPlaybackSettings(rate); +} + +status_t StagefrightPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + return mPlayer->getPlaybackSettings(rate); +} + status_t StagefrightPlayer::getMetadata( const media::Metadata::Filter& /* ids */, Parcel *records) { using media::Metadata; diff --git a/media/libmediaplayerservice/StagefrightPlayer.h b/media/libmediaplayerservice/StagefrightPlayer.h index e6c30ff..96013df 100644 --- a/media/libmediaplayerservice/StagefrightPlayer.h +++ b/media/libmediaplayerservice/StagefrightPlayer.h @@ -60,6 +60,8 @@ public: virtual void setAudioSink(const sp<AudioSink> &audioSink); virtual status_t setParameter(int key, const Parcel &request); virtual status_t getParameter(int key, Parcel *reply); + virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate); + virtual status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); virtual status_t getMetadata( const media::Metadata::Filter& ids, Parcel *records); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index 8a0b060..aa19a25 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -69,8 +69,9 @@ static void addBatteryData(uint32_t params) { } -StagefrightRecorder::StagefrightRecorder() - : mWriter(NULL), +StagefrightRecorder::StagefrightRecorder(const String16 &opPackageName) + : MediaRecorderBase(opPackageName), + mWriter(NULL), mOutputFd(-1), mAudioSource(AUDIO_SOURCE_CNT), mVideoSource(VIDEO_SOURCE_LIST_END), @@ -905,6 +906,7 @@ sp<MediaSource> StagefrightRecorder::createAudioSource() { sp<AudioSource> audioSource = new AudioSource( mAudioSource, + mOpPackageName, mSampleRate, mAudioChannels); diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h index 8fa5bfa..1425f59 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.h +++ b/media/libmediaplayerservice/StagefrightRecorder.h @@ -40,7 +40,7 @@ class SurfaceMediaSource; struct ALooper; struct StagefrightRecorder : public MediaRecorderBase { - StagefrightRecorder(); + StagefrightRecorder(const String16 &opPackageName); virtual ~StagefrightRecorder(); virtual status_t init(); diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp index 7eaa0e0..5e7b644 100644 --- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp +++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp @@ -1065,6 +1065,7 @@ sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { const char *mime; CHECK(meta->findCString(kKeyMIMEType, &mime)); + format->setString("mime", mime); int32_t trackType; if (!strncasecmp(mime, "video/", 6)) { @@ -1085,8 +1086,6 @@ sp<AMessage> NuPlayer::GenericSource::getTrackInfo(size_t trackIndex) const { format->setString("language", lang); if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { - format->setString("mime", mime); - int32_t isAutoselect = 1, isDefault = 0, isForced = 0; meta->findInt32(kKeyTrackIsAutoselect, &isAutoselect); meta->findInt32(kKeyTrackIsDefault, &isDefault); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index b670d68..9963353 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -37,6 +37,9 @@ #include <cutils/properties.h> +#include <media/AudioResamplerPublic.h> +#include <media/AVSyncSettings.h> + #include <media/stagefright/foundation/hexdump.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/ADebug.h> @@ -45,7 +48,9 @@ #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MetaData.h> + #include <gui/IGraphicBufferProducer.h> +#include <gui/Surface.h> #include "avc_utils.h" @@ -96,16 +101,16 @@ private: }; struct NuPlayer::SetSurfaceAction : public Action { - SetSurfaceAction(const sp<NativeWindowWrapper> &wrapper) - : mWrapper(wrapper) { + SetSurfaceAction(const sp<Surface> &surface) + : mSurface(surface) { } virtual void execute(NuPlayer *player) { - player->performSetSurface(mWrapper); + player->performSetSurface(mSurface); } private: - sp<NativeWindowWrapper> mWrapper; + sp<Surface> mSurface; DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction); }; @@ -180,7 +185,8 @@ NuPlayer::NuPlayer() mFlushingVideo(NONE), mResumePending(false), mVideoScalingMode(NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW), - mPlaybackRate(1.0), + mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT), + mVideoFpsHint(-1.f), mStarted(false), mPaused(false), mPausedByClient(false) { @@ -307,15 +313,12 @@ void NuPlayer::prepareAsync() { void NuPlayer::setVideoSurfaceTextureAsync( const sp<IGraphicBufferProducer> &bufferProducer) { - sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, this); + sp<AMessage> msg = new AMessage(kWhatSetVideoSurface, this); if (bufferProducer == NULL) { - msg->setObject("native-window", NULL); + msg->setObject("surface", NULL); } else { - msg->setObject( - "native-window", - new NativeWindowWrapper( - new Surface(bufferProducer, true /* controlledByApp */))); + msg->setObject("surface", new Surface(bufferProducer, true /* controlledByApp */)); } msg->post(); @@ -331,10 +334,61 @@ void NuPlayer::start() { (new AMessage(kWhatStart, this))->post(); } -void NuPlayer::setPlaybackRate(float rate) { - sp<AMessage> msg = new AMessage(kWhatSetRate, this); - msg->setFloat("rate", rate); - msg->post(); +status_t NuPlayer::setPlaybackSettings(const AudioPlaybackRate &rate) { + // do some cursory validation of the settings here. audio modes are + // only validated when set on the audiosink. + if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN) + || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX + || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN + || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) { + return BAD_VALUE; + } + sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this); + writeToAMessage(msg, rate); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, rate); + } + } + return err; +} + +status_t NuPlayer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { + sp<AMessage> msg = new AMessage(kWhatConfigSync, this); + writeToAMessage(msg, sync, videoFpsHint); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::getSyncSettings( + AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) { + sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, sync, videoFps); + } + } + return err; } void NuPlayer::pause() { @@ -368,23 +422,23 @@ void NuPlayer::writeTrackInfo( int32_t trackType; CHECK(format->findInt32("type", &trackType)); + AString mime; + CHECK(format->findString("mime", &mime)); + AString lang; CHECK(format->findString("language", &lang)); reply->writeInt32(2); // write something non-zero reply->writeInt32(trackType); + reply->writeString16(String16(mime.c_str())); reply->writeString16(String16(lang.c_str())); if (trackType == MEDIA_TRACK_TYPE_SUBTITLE) { - AString mime; - CHECK(format->findString("mime", &mime)); - int32_t isAuto, isDefault, isForced; CHECK(format->findInt32("auto", &isAuto)); CHECK(format->findInt32("default", &isDefault)); CHECK(format->findInt32("forced", &isForced)); - reply->writeString16(String16(mime.c_str())); reply->writeInt32(isAuto); reply->writeInt32(isDefault); reply->writeInt32(isForced); @@ -555,15 +609,15 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { break; } - case kWhatSetVideoNativeWindow: + case kWhatSetVideoSurface: { - ALOGV("kWhatSetVideoNativeWindow"); + ALOGV("kWhatSetVideoSurface"); sp<RefBase> obj; - CHECK(msg->findObject("native-window", &obj)); - + CHECK(msg->findObject("surface", &obj)); + sp<Surface> surface = static_cast<Surface *>(obj.get()); if (mSource == NULL || mSource->getFormat(false /* audio */) == NULL) { - performSetSurface(static_cast<NativeWindowWrapper *>(obj.get())); + performSetSurface(surface); break; } @@ -571,9 +625,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { new FlushDecoderAction(FLUSH_CMD_FLUSH /* audio */, FLUSH_CMD_SHUTDOWN /* video */)); - mDeferredActions.push_back( - new SetSurfaceAction( - static_cast<NativeWindowWrapper *>(obj.get()))); + mDeferredActions.push_back(new SetSurfaceAction(surface)); if (obj != NULL) { if (mStarted) { @@ -627,12 +679,28 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { break; } - case kWhatSetRate: + case kWhatConfigPlayback: { - ALOGV("kWhatSetRate"); - CHECK(msg->findFloat("rate", &mPlaybackRate)); + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate /* sanitized */; + readFromAMessage(msg, &rate); + status_t err = OK; if (mRenderer != NULL) { - mRenderer->setPlaybackRate(mPlaybackRate); + err = mRenderer->setPlaybackSettings(rate); + } + if (err == OK) { + if (rate.mSpeed == 0.f) { + onPause(); + // save all other settings (using non-paused speed) + // so we can restore them on start + AudioPlaybackRate newRate = rate; + newRate.mSpeed = mPlaybackSettings.mSpeed; + mPlaybackSettings = newRate; + } else { /* rate.mSpeed != 0.f */ + onResume(); + mPlaybackSettings = rate; + } } if (mVideoDecoder != NULL) { @@ -640,11 +708,86 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { int32_t rate; if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) { sp<AMessage> params = new AMessage(); - params->setFloat("operating-rate", rate * mPlaybackRate); + params->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed); mVideoDecoder->setParameters(params); } } + sp<AMessage> response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetPlaybackSettings: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate = mPlaybackSettings; + status_t err = OK; + if (mRenderer != NULL) { + err = mRenderer->getPlaybackSettings(&rate); + } + if (err == OK) { + // get playback settings used by renderer, as it may be + // slightly off due to audiosink not taking small changes. + mPlaybackSettings = rate; + if (mPaused) { + rate.mSpeed = 0.f; + } + } + sp<AMessage> response = new AMessage; + if (err == OK) { + writeToAMessage(response, rate); + } + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatConfigSync: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + ALOGV("kWhatConfigSync"); + AVSyncSettings sync; + float videoFpsHint; + readFromAMessage(msg, &sync, &videoFpsHint); + status_t err = OK; + if (mRenderer != NULL) { + err = mRenderer->setSyncSettings(sync, videoFpsHint); + } + if (err == OK) { + mSyncSettings = sync; + mVideoFpsHint = videoFpsHint; + } + sp<AMessage> response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetSyncSettings: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AVSyncSettings sync = mSyncSettings; + float videoFps = mVideoFpsHint; + status_t err = OK; + if (mRenderer != NULL) { + err = mRenderer->getSyncSettings(&sync, &videoFps); + if (err == OK) { + mSyncSettings = sync; + mVideoFpsHint = videoFps; + } + } + sp<AMessage> response = new AMessage; + if (err == OK) { + writeToAMessage(response, sync, videoFps); + } + response->setInt32("err", err); + response->postReply(replyID); break; } @@ -667,7 +810,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { // initialize video before audio because successful initialization of // video may change deep buffer mode of audio. - if (mNativeWindow != NULL) { + if (mSurface != NULL) { instantiateDecoder(false, &mVideoDecoder); } @@ -715,7 +858,7 @@ void NuPlayer::onMessageReceived(const sp<AMessage> &msg) { } if ((mAudioDecoder == NULL && mAudioSink != NULL) - || (mVideoDecoder == NULL && mNativeWindow != NULL)) { + || (mVideoDecoder == NULL && mSurface != NULL)) { msg->post(100000ll); mScanSourcesPending = true; } @@ -1061,7 +1204,7 @@ status_t NuPlayer::onInstantiateSecureDecoders() { // TRICKY: We rely on mRenderer being null, so that decoder does not start requesting // data on instantiation. - if (mNativeWindow != NULL) { + if (mSurface != NULL) { err = instantiateDecoder(false, &mVideoDecoder); if (err != OK) { return err; @@ -1114,8 +1257,12 @@ void NuPlayer::onStart() { mRendererLooper->setName("NuPlayerRenderer"); mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO); mRendererLooper->registerHandler(mRenderer); - if (mPlaybackRate != 1.0) { - mRenderer->setPlaybackRate(mPlaybackRate); + + status_t err = mRenderer->setPlaybackSettings(mPlaybackSettings); + if (err != OK) { + mSource->stop(); + notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); + return; } sp<MetaData> meta = getFileMeta(); @@ -1282,7 +1429,7 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) { sp<MetaData> meta = getFileMeta(); int32_t rate; if (meta != NULL && meta->findInt32(kKeyFrameRate, &rate) && rate > 0) { - format->setFloat("operating-rate", rate * mPlaybackRate); + format->setFloat("operating-rate", rate * mPlaybackSettings.mSpeed); } } @@ -1304,10 +1451,10 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<DecoderBase> *decoder) { notify->setInt32("generation", mVideoDecoderGeneration); *decoder = new Decoder( - notify, mSource, mRenderer, mNativeWindow, mCCDecoder); + notify, mSource, mRenderer, mSurface, mCCDecoder); // enable FRC if high-quality AV sync is requested, even if not - // queuing to native window, as this will even improve textureview + // directly queuing to display, as this will even improve textureview // playback. { char value[PROPERTY_VALUE_MAX]; @@ -1479,9 +1626,8 @@ void NuPlayer::queueDecoderShutdown( status_t NuPlayer::setVideoScalingMode(int32_t mode) { mVideoScalingMode = mode; - if (mNativeWindow != NULL) { - status_t ret = native_window_set_scaling_mode( - mNativeWindow->getNativeWindow().get(), mVideoScalingMode); + if (mSurface != NULL) { + status_t ret = native_window_set_scaling_mode(mSurface.get(), mVideoScalingMode); if (ret != OK) { ALOGE("Failed to set scaling mode (%d): %s", -ret, strerror(-ret)); @@ -1675,10 +1821,10 @@ void NuPlayer::performScanSources() { } } -void NuPlayer::performSetSurface(const sp<NativeWindowWrapper> &wrapper) { +void NuPlayer::performSetSurface(const sp<Surface> &surface) { ALOGV("performSetSurface"); - mNativeWindow = wrapper; + mSurface = surface; // XXX - ignore error from setVideoScalingMode for now setVideoScalingMode(mVideoScalingMode); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h index 14bdb01..fcf6841 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h @@ -18,14 +18,16 @@ #define NU_PLAYER_H_ +#include <media/AudioResamplerPublic.h> #include <media/MediaPlayerInterface.h> #include <media/stagefright/foundation/AHandler.h> -#include <media/stagefright/NativeWindowWrapper.h> namespace android { struct ABuffer; struct AMessage; +struct AudioPlaybackRate; +struct AVSyncSettings; class IDataSource; class MetaData; struct NuPlayerDriver; @@ -54,7 +56,11 @@ struct NuPlayer : public AHandler { const sp<IGraphicBufferProducer> &bufferProducer); void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink); - void setPlaybackRate(float rate); + status_t setPlaybackSettings(const AudioPlaybackRate &rate); + status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint); + status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); + void start(); void pause(); @@ -105,10 +111,13 @@ private: enum { kWhatSetDataSource = '=DaS', kWhatPrepare = 'prep', - kWhatSetVideoNativeWindow = '=NaW', + kWhatSetVideoSurface = '=VSu', kWhatSetAudioSink = '=AuS', kWhatMoreDataQueued = 'more', - kWhatSetRate = 'setR', + kWhatConfigPlayback = 'cfPB', + kWhatConfigSync = 'cfSy', + kWhatGetPlaybackSettings = 'gPbS', + kWhatGetSyncSettings = 'gSyS', kWhatStart = 'strt', kWhatScanSources = 'scan', kWhatVideoNotify = 'vidN', @@ -131,7 +140,7 @@ private: uid_t mUID; sp<Source> mSource; uint32_t mSourceFlags; - sp<NativeWindowWrapper> mNativeWindow; + sp<Surface> mSurface; sp<MediaPlayerBase::AudioSink> mAudioSink; sp<DecoderBase> mVideoDecoder; bool mOffloadAudio; @@ -180,7 +189,9 @@ private: int32_t mVideoScalingMode; - float mPlaybackRate; + AudioPlaybackRate mPlaybackSettings; + AVSyncSettings mSyncSettings; + float mVideoFpsHint; bool mStarted; // Actual pause state, either as requested by client or due to buffering. @@ -239,7 +250,7 @@ private: void performDecoderFlush(FlushCommand audio, FlushCommand video); void performReset(); void performScanSources(); - void performSetSurface(const sp<NativeWindowWrapper> &wrapper); + void performSetSurface(const sp<Surface> &wrapper); void performResumeDecoders(bool needNotify); void onSourceNotify(const sp<AMessage> &msg); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp index 3c4d695..376c93a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp @@ -33,6 +33,8 @@ #include <media/stagefright/MediaDefs.h> #include <media/stagefright/MediaErrors.h> +#include <gui/Surface.h> + #include "avc_utils.h" #include "ATSParser.h" @@ -42,10 +44,10 @@ NuPlayer::Decoder::Decoder( const sp<AMessage> ¬ify, const sp<Source> &source, const sp<Renderer> &renderer, - const sp<NativeWindowWrapper> &nativeWindow, + const sp<Surface> &surface, const sp<CCDecoder> &ccDecoder) : DecoderBase(notify), - mNativeWindow(nativeWindow), + mSurface(surface), mSource(source), mRenderer(renderer), mCCDecoder(ccDecoder), @@ -178,14 +180,9 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { mIsAudio = !strncasecmp("audio/", mime.c_str(), 6); mIsVideoAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str()); - sp<Surface> surface = NULL; - if (mNativeWindow != NULL) { - surface = mNativeWindow->getSurfaceTextureClient(); - } - mComponentName = mime; mComponentName.append(" decoder"); - ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), surface.get()); + ALOGV("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mSurface.get()); mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); int32_t secure = 0; @@ -210,17 +207,17 @@ void NuPlayer::Decoder::onConfigure(const sp<AMessage> &format) { mCodec->getName(&mComponentName); status_t err; - if (mNativeWindow != NULL) { + if (mSurface != NULL) { // disconnect from surface as MediaCodec will reconnect err = native_window_api_disconnect( - surface.get(), NATIVE_WINDOW_API_MEDIA); + mSurface.get(), NATIVE_WINDOW_API_MEDIA); // We treat this as a warning, as this is a preparatory step. // Codec will try to connect to the surface, which is where // any error signaling will occur. ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err); } err = mCodec->configure( - format, surface, NULL /* crypto */, 0 /* flags */); + format, mSurface, NULL /* crypto */, 0 /* flags */); if (err != OK) { ALOGE("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); mCodec->release(); @@ -337,12 +334,10 @@ void NuPlayer::Decoder::onShutdown(bool notifyComplete) { mCodec = NULL; ++mBufferGeneration; - if (mNativeWindow != NULL) { + if (mSurface != NULL) { // reconnect to surface as MediaCodec disconnected from it status_t error = - native_window_api_connect( - mNativeWindow->getNativeWindow().get(), - NATIVE_WINDOW_API_MEDIA); + native_window_api_connect(mSurface.get(), NATIVE_WINDOW_API_MEDIA); ALOGW_IF(error != NO_ERROR, "[%s] failed to connect to native window, error=%d", mComponentName.c_str(), error); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h index dd84620..070d51a 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.h @@ -27,7 +27,7 @@ struct NuPlayer::Decoder : public DecoderBase { Decoder(const sp<AMessage> ¬ify, const sp<Source> &source, const sp<Renderer> &renderer = NULL, - const sp<NativeWindowWrapper> &nativeWindow = NULL, + const sp<Surface> &surface = NULL, const sp<CCDecoder> &ccDecoder = NULL); virtual void getStats( @@ -54,7 +54,7 @@ private: kWhatRenderBuffer = 'rndr', }; - sp<NativeWindowWrapper> mNativeWindow; + sp<Surface> mSurface; sp<Source> mSource; sp<Renderer> mRenderer; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp index 04a324c..231f2e1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp @@ -360,9 +360,32 @@ bool NuPlayerDriver::isPlaying() { return mState == STATE_RUNNING && !mAtEOS; } -status_t NuPlayerDriver::setPlaybackRate(float rate) { - mPlayer->setPlaybackRate(rate); - return OK; +status_t NuPlayerDriver::setPlaybackSettings(const AudioPlaybackRate &rate) { + Mutex::Autolock autoLock(mLock); + status_t err = mPlayer->setPlaybackSettings(rate); + if (err == OK) { + if (rate.mSpeed == 0.f && mState == STATE_RUNNING) { + mState = STATE_PAUSED; + // try to update position + (void)mPlayer->getCurrentPosition(&mPositionUs); + notifyListener_l(MEDIA_PAUSED); + } else if (rate.mSpeed != 0.f && mState == STATE_PAUSED) { + mState = STATE_RUNNING; + } + } + return err; +} + +status_t NuPlayerDriver::getPlaybackSettings(AudioPlaybackRate *rate) { + return mPlayer->getPlaybackSettings(rate); +} + +status_t NuPlayerDriver::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { + return mPlayer->setSyncSettings(sync, videoFpsHint); +} + +status_t NuPlayerDriver::getSyncSettings(AVSyncSettings *sync, float *videoFps) { + return mPlayer->getSyncSettings(sync, videoFps); } status_t NuPlayerDriver::seekTo(int msec) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h index 65f170e..9da7fc1 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h @@ -49,7 +49,10 @@ struct NuPlayerDriver : public MediaPlayerInterface { virtual status_t stop(); virtual status_t pause(); virtual bool isPlaying(); - virtual status_t setPlaybackRate(float rate); + virtual status_t setPlaybackSettings(const AudioPlaybackRate &rate); + virtual status_t getPlaybackSettings(AudioPlaybackRate *rate); + virtual status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint); + virtual status_t getSyncSettings(AVSyncSettings *sync, float *videoFps); virtual status_t seekTo(int msec); virtual status_t getCurrentPosition(int *msec); virtual status_t getDuration(int *msec); diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp index f229452..ae01cfc 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp @@ -66,7 +66,7 @@ NuPlayer::Renderer::Renderer( mVideoQueueGeneration(0), mAudioDrainGeneration(0), mVideoDrainGeneration(0), - mPlaybackRate(1.0), + mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT), mAudioFirstAnchorTimeMediaUs(-1), mAnchorTimeMediaUs(-1), mAnchorNumFramesWritten(-1), @@ -89,6 +89,8 @@ NuPlayer::Renderer::Renderer( mLastAudioBufferDrained(0), mWakeLock(new AWakeLock()) { mMediaClock = new MediaClock; + mPlaybackRate = mPlaybackSettings.mSpeed; + mMediaClock->setPlaybackRate(mPlaybackRate); } NuPlayer::Renderer::~Renderer() { @@ -121,10 +123,111 @@ void NuPlayer::Renderer::queueEOS(bool audio, status_t finalResult) { msg->post(); } -void NuPlayer::Renderer::setPlaybackRate(float rate) { - sp<AMessage> msg = new AMessage(kWhatSetRate, this); - msg->setFloat("rate", rate); - msg->post(); +status_t NuPlayer::Renderer::setPlaybackSettings(const AudioPlaybackRate &rate) { + sp<AMessage> msg = new AMessage(kWhatConfigPlayback, this); + writeToAMessage(msg, rate); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) { + if (rate.mSpeed == 0.f) { + onPause(); + // don't call audiosink's setPlaybackRate if pausing, as pitch does not + // have to correspond to the any non-0 speed (e.g old speed). Keep + // settings nonetheless, using the old speed, in case audiosink changes. + AudioPlaybackRate newRate = rate; + newRate.mSpeed = mPlaybackSettings.mSpeed; + mPlaybackSettings = newRate; + return OK; + } + + if (mAudioSink != NULL) { + status_t err = mAudioSink->setPlaybackRate(rate); + if (err != OK) { + return err; + } + } + mPlaybackSettings = rate; + mPlaybackRate = rate.mSpeed; + mMediaClock->setPlaybackRate(mPlaybackRate); + return OK; +} + +status_t NuPlayer::Renderer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + sp<AMessage> msg = new AMessage(kWhatGetPlaybackSettings, this); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, rate); + } + } + return err; +} + +status_t NuPlayer::Renderer::onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + if (mAudioSink != NULL) { + status_t err = mAudioSink->getPlaybackRate(rate); + if (err == OK) { + if (!isAudioPlaybackRateEqual(*rate, mPlaybackSettings)) { + ALOGW("correcting mismatch in internal/external playback rate"); + } + // get playback settings used by audiosink, as it may be + // slightly off due to audiosink not taking small changes. + mPlaybackSettings = *rate; + if (mPaused) { + rate->mSpeed = 0.f; + } + } + return err; + } + *rate = mPlaybackSettings; + return OK; +} + +status_t NuPlayer::Renderer::setSyncSettings(const AVSyncSettings &sync, float videoFpsHint) { + sp<AMessage> msg = new AMessage(kWhatConfigSync, this); + writeToAMessage(msg, sync, videoFpsHint); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + } + return err; +} + +status_t NuPlayer::Renderer::onConfigSync(const AVSyncSettings &sync, float videoFpsHint __unused) { + if (sync.mSource != AVSYNC_SOURCE_DEFAULT) { + return BAD_VALUE; + } + // TODO: support sync sources + return INVALID_OPERATION; +} + +status_t NuPlayer::Renderer::getSyncSettings(AVSyncSettings *sync, float *videoFps) { + sp<AMessage> msg = new AMessage(kWhatGetSyncSettings, this); + sp<AMessage> response; + status_t err = msg->postAndAwaitResponse(&response); + if (err == OK && response != NULL) { + CHECK(response->findInt32("err", &err)); + if (err == OK) { + readFromAMessage(response, sync, videoFps); + } + } + return err; +} + +status_t NuPlayer::Renderer::onGetSyncSettings( + AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */) { + *sync = mSyncSettings; + *videoFps = -1.f; + return OK; } void NuPlayer::Renderer::flush(bool audio, bool notifyComplete) { @@ -365,13 +468,63 @@ void NuPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { break; } - case kWhatSetRate: + case kWhatConfigPlayback: { - CHECK(msg->findFloat("rate", &mPlaybackRate)); - int32_t ratePermille = (int32_t)(0.5f + 1000 * mPlaybackRate); - mPlaybackRate = ratePermille / 1000.0f; - mMediaClock->setPlaybackRate(mPlaybackRate); - mAudioSink->setPlaybackRatePermille(ratePermille); + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate; + readFromAMessage(msg, &rate); + status_t err = onConfigPlayback(rate); + sp<AMessage> response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetPlaybackSettings: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AudioPlaybackRate rate = AUDIO_PLAYBACK_RATE_DEFAULT; + status_t err = onGetPlaybackSettings(&rate); + sp<AMessage> response = new AMessage; + if (err == OK) { + writeToAMessage(response, rate); + } + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatConfigSync: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + AVSyncSettings sync; + float videoFpsHint; + readFromAMessage(msg, &sync, &videoFpsHint); + status_t err = onConfigSync(sync, videoFpsHint); + sp<AMessage> response = new AMessage; + response->setInt32("err", err); + response->postReply(replyID); + break; + } + + case kWhatGetSyncSettings: + { + sp<AReplyToken> replyID; + CHECK(msg->senderAwaitsResponse(&replyID)); + + ALOGV("kWhatGetSyncSettings"); + AVSyncSettings sync; + float videoFps = -1.f; + status_t err = onGetSyncSettings(&sync, &videoFps); + sp<AMessage> response = new AMessage; + if (err == OK) { + writeToAMessage(response, sync, videoFps); + } + response->setInt32("err", err); + response->postReply(replyID); break; } @@ -1176,7 +1329,6 @@ void NuPlayer::Renderer::onEnableOffloadAudio() { void NuPlayer::Renderer::onPause() { if (mPaused) { - ALOGW("Renderer::onPause() called while already paused!"); return; } @@ -1214,6 +1366,12 @@ void NuPlayer::Renderer::onResume() { { Mutex::Autolock autoLock(mLock); mPaused = false; + + // configure audiosink as we did not do it when pausing + if (mAudioSink != NULL) { + mAudioSink->setPlaybackRate(mPlaybackSettings); + } + mMediaClock->setPlaybackRate(mPlaybackRate); if (!mAudioQueue.empty()) { @@ -1433,10 +1591,10 @@ status_t NuPlayer::Renderer::onOpenAudioSink( &offloadInfo); if (err == OK) { - if (mPlaybackRate != 1.0) { - mAudioSink->setPlaybackRatePermille( - (int32_t)(mPlaybackRate * 1000 + 0.5f)); - } + err = mAudioSink->setPlaybackRate(mPlaybackSettings); + } + + if (err == OK) { // If the playback is offloaded to h/w, we pass // the HAL some metadata information. // We don't want to do this for PCM because it @@ -1486,16 +1644,15 @@ status_t NuPlayer::Renderer::onOpenAudioSink( NULL, NULL, (audio_output_flags_t)pcmFlags); + if (err == OK) { + err = mAudioSink->setPlaybackRate(mPlaybackSettings); + } if (err != OK) { ALOGW("openAudioSink: non offloaded open failed status: %d", err); mCurrentPcmInfo = AUDIO_PCMINFO_INITIALIZER; return err; } mCurrentPcmInfo = info; - if (mPlaybackRate != 1.0) { - mAudioSink->setPlaybackRatePermille( - (int32_t)(mPlaybackRate * 1000 + 0.5f)); - } mAudioSink->start(); } if (audioSinkChanged) { diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h index 38843d5..928b71b 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h +++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h @@ -18,6 +18,9 @@ #define NUPLAYER_RENDERER_H_ +#include <media/AudioResamplerPublic.h> +#include <media/AVSyncSettings.h> + #include "NuPlayer.h" namespace android { @@ -48,7 +51,10 @@ struct NuPlayer::Renderer : public AHandler { void queueEOS(bool audio, status_t finalResult); - void setPlaybackRate(float rate); + status_t setPlaybackSettings(const AudioPlaybackRate &rate /* sanitized */); + status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + status_t setSyncSettings(const AVSyncSettings &sync, float videoFpsHint); + status_t getSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); void flush(bool audio, bool notifyComplete); @@ -102,7 +108,10 @@ private: kWhatPostDrainVideoQueue = 'pDVQ', kWhatQueueBuffer = 'queB', kWhatQueueEOS = 'qEOS', - kWhatSetRate = 'setR', + kWhatConfigPlayback = 'cfPB', + kWhatConfigSync = 'cfSy', + kWhatGetPlaybackSettings = 'gPbS', + kWhatGetSyncSettings = 'gSyS', kWhatFlush = 'flus', kWhatPause = 'paus', kWhatResume = 'resm', @@ -141,7 +150,12 @@ private: int32_t mVideoDrainGeneration; sp<MediaClock> mMediaClock; - float mPlaybackRate; + float mPlaybackRate; // audio track rate + + AudioPlaybackRate mPlaybackSettings; + AVSyncSettings mSyncSettings; + float mVideoFpsHint; + int64_t mAudioFirstAnchorTimeMediaUs; int64_t mAnchorTimeMediaUs; int64_t mAnchorNumFramesWritten; @@ -217,6 +231,11 @@ private: void onAudioSinkChanged(); void onDisableOffloadAudio(); void onEnableOffloadAudio(); + status_t onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */); + status_t onGetPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); + status_t onConfigSync(const AVSyncSettings &sync, float videoFpsHint); + status_t onGetSyncSettings(AVSyncSettings *sync /* nonnull */, float *videoFps /* nonnull */); + void onPause(); void onResume(); void onSetVideoFrameRate(float fps); @@ -252,6 +271,6 @@ private: DISALLOW_EVIL_CONSTRUCTORS(Renderer); }; -} // namespace android +} // namespace android #endif // NUPLAYER_RENDERER_H_ diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index c7df5a0..7b87676 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -24,6 +24,8 @@ #include <inttypes.h> #include <utils/Trace.h> +#include <gui/Surface.h> + #include <media/stagefright/ACodec.h> #include <binder/MemoryDealer.h> @@ -37,7 +39,6 @@ #include <media/stagefright/BufferProducerWrapper.h> #include <media/stagefright/MediaCodecList.h> #include <media/stagefright/MediaDefs.h> -#include <media/stagefright/NativeWindowWrapper.h> #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> @@ -806,6 +807,11 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { return err; mNumUndequeuedBuffers = minUndequeuedBuffers; + if (!mStoreMetaDataInOutputBuffers) { + static_cast<Surface*>(mNativeWindow.get()) + ->getIGraphicBufferProducer()->allowAllocation(true); + } + ALOGV("[%s] Allocating %u buffers from a native window of size %u on " "output port", mComponentName.c_str(), bufferCount, bufferSize); @@ -864,6 +870,11 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { } } + if (!mStoreMetaDataInOutputBuffers) { + static_cast<Surface*>(mNativeWindow.get()) + ->getIGraphicBufferProducer()->allowAllocation(false); + } + return err; } @@ -1306,9 +1317,8 @@ status_t ACodec::configureCodec( } } if (haveNativeWindow) { - sp<NativeWindowWrapper> windowWrapper( - static_cast<NativeWindowWrapper *>(obj.get())); - sp<ANativeWindow> nativeWindow = windowWrapper->getNativeWindow(); + sp<ANativeWindow> nativeWindow = + static_cast<ANativeWindow *>(static_cast<Surface *>(obj.get())); // START of temporary support for automatic FRC - THIS WILL BE REMOVED int32_t autoFrc; @@ -1467,10 +1477,8 @@ status_t ACodec::configureCodec( } if (haveNativeWindow) { - sp<NativeWindowWrapper> nativeWindow( - static_cast<NativeWindowWrapper *>(obj.get())); - CHECK(nativeWindow != NULL); - mNativeWindow = nativeWindow->getNativeWindow(); + mNativeWindow = static_cast<Surface *>(obj.get()); + CHECK(mNativeWindow != NULL); native_window_set_scaling_mode( mNativeWindow.get(), NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); @@ -4909,7 +4917,10 @@ bool ACodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { CHECK(mCodec->mNode == 0); OMXClient client; - CHECK_EQ(client.connect(), (status_t)OK); + if (client.connect() != OK) { + mCodec->signalError(OMX_ErrorUndefined, NO_INIT); + return false; + } sp<IOMX> omx = client.interface(); diff --git a/media/libstagefright/AudioPlayer.cpp b/media/libstagefright/AudioPlayer.cpp index e24824b..dd9d393 100644 --- a/media/libstagefright/AudioPlayer.cpp +++ b/media/libstagefright/AudioPlayer.cpp @@ -408,11 +408,22 @@ void AudioPlayer::notifyAudioEOS() { } } -status_t AudioPlayer::setPlaybackRatePermille(int32_t ratePermille) { +status_t AudioPlayer::setPlaybackRate(const AudioPlaybackRate &rate) { if (mAudioSink.get() != NULL) { - return mAudioSink->setPlaybackRatePermille(ratePermille); + return mAudioSink->setPlaybackRate(rate); } else if (mAudioTrack != 0){ - return mAudioTrack->setSampleRate(ratePermille * mSampleRate / 1000); + return mAudioTrack->setPlaybackRate(rate); + } else { + return NO_INIT; + } +} + +status_t AudioPlayer::getPlaybackRate(AudioPlaybackRate *rate /* nonnull */) { + if (mAudioSink.get() != NULL) { + return mAudioSink->getPlaybackRate(rate); + } else if (mAudioTrack != 0) { + *rate = mAudioTrack->getPlaybackRate(); + return OK; } else { return NO_INIT; } diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp index 804f131..e5a6a9b 100644 --- a/media/libstagefright/AudioSource.cpp +++ b/media/libstagefright/AudioSource.cpp @@ -50,7 +50,8 @@ static void AudioRecordCallbackFunction(int event, void *user, void *info) { } AudioSource::AudioSource( - audio_source_t inputSource, uint32_t sampleRate, uint32_t channelCount) + audio_source_t inputSource, const String16 &opPackageName, uint32_t sampleRate, + uint32_t channelCount) : mStarted(false), mSampleRate(sampleRate), mPrevSampleTimeUs(0), @@ -78,6 +79,7 @@ AudioSource::AudioSource( mRecord = new AudioRecord( inputSource, sampleRate, AUDIO_FORMAT_PCM_16_BIT, audio_channel_in_mask_from_count(channelCount), + opPackageName, (size_t) (bufCount * frameCount), AudioRecordCallbackFunction, this, diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp index c14625d..df01e7c 100644 --- a/media/libstagefright/AwesomePlayer.cpp +++ b/media/libstagefright/AwesomePlayer.cpp @@ -241,6 +241,8 @@ AwesomePlayer::AwesomePlayer() mClockEstimator = new WindowedLinearFitEstimator(); + mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT; + reset(); } @@ -1009,6 +1011,10 @@ status_t AwesomePlayer::play_l() { return err; } } + + if (mAudioPlayer != NULL) { + mAudioPlayer->setPlaybackRate(mPlaybackSettings); + } } if (mTimeSource == NULL && mAudioPlayer == NULL) { @@ -1131,6 +1137,10 @@ status_t AwesomePlayer::startAudioPlayer_l(bool sendErrorNotification) { } if (err == OK) { + err = mAudioPlayer->setPlaybackRate(mPlaybackSettings); + } + + if (err == OK) { modifyFlags(AUDIO_RUNNING, SET); mWatchForAudioEOS = true; @@ -2553,14 +2563,6 @@ status_t AwesomePlayer::setParameter(int key, const Parcel &request) { { return setCacheStatCollectFreq(request); } - case KEY_PARAMETER_PLAYBACK_RATE_PERMILLE: - { - if (mAudioPlayer != NULL) { - return mAudioPlayer->setPlaybackRatePermille(request.readInt32()); - } else { - return NO_INIT; - } - } default: { return ERROR_UNSUPPORTED; @@ -2597,6 +2599,58 @@ status_t AwesomePlayer::getParameter(int key, Parcel *reply) { } } +status_t AwesomePlayer::setPlaybackSettings(const AudioPlaybackRate &rate) { + Mutex::Autolock autoLock(mLock); + // cursory sanity check for non-audio and paused cases + if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN) + || rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX + || rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN + || rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) { + return BAD_VALUE; + } + + status_t err = OK; + if (rate.mSpeed == 0.f) { + if (mFlags & PLAYING) { + modifyFlags(CACHE_UNDERRUN, CLEAR); // same as pause + err = pause_l(); + } + if (err == OK) { + // save settings (using old speed) in case player is resumed + AudioPlaybackRate newRate = rate; + newRate.mSpeed = mPlaybackSettings.mSpeed; + mPlaybackSettings = newRate; + } + return err; + } + if (mAudioPlayer != NULL) { + err = mAudioPlayer->setPlaybackRate(rate); + } + if (err == OK) { + mPlaybackSettings = rate; + if (!(mFlags & PLAYING)) { + play_l(); + } + } + return err; +} + +status_t AwesomePlayer::getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */) { + if (mAudioPlayer != NULL) { + status_t err = mAudioPlayer->getPlaybackRate(rate); + if (err == OK) { + mPlaybackSettings = *rate; + Mutex::Autolock autoLock(mLock); + if (!(mFlags & PLAYING)) { + rate->mSpeed = 0.f; + } + } + return err; + } + *rate = mPlaybackSettings; + return OK; +} + status_t AwesomePlayer::getTrackInfo(Parcel *reply) const { Mutex::Autolock autoLock(mLock); size_t trackCount = mExtractor->countTracks(); diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp index 55e3c19..2e54e8c 100644 --- a/media/libstagefright/MP3Extractor.cpp +++ b/media/libstagefright/MP3Extractor.cpp @@ -282,6 +282,41 @@ MP3Extractor::MP3Extractor( mFirstFramePos = pos; mFixedHeader = header; + mMeta = new MetaData; + sp<XINGSeeker> seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos); + + if (seeker == NULL) { + mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos); + } else { + mSeeker = seeker; + int encd = seeker->getEncoderDelay(); + int encp = seeker->getEncoderPadding(); + if (encd != 0 || encp != 0) { + mMeta->setInt32(kKeyEncoderDelay, encd); + mMeta->setInt32(kKeyEncoderPadding, encp); + } + } + + if (mSeeker != NULL) { + // While it is safe to send the XING/VBRI frame to the decoder, this will + // result in an extra 1152 samples being output. In addition, the bitrate + // of the Xing header might not match the rest of the file, which could + // lead to problems when seeking. The real first frame to decode is after + // the XING/VBRI frame, so skip there. + size_t frame_size; + int sample_rate; + int num_channels; + int bitrate; + GetMPEGAudioFrameSize( + header, &frame_size, &sample_rate, &num_channels, &bitrate); + pos += frame_size; + if (!Resync(mDataSource, 0, &pos, &post_id3_pos, &header)) { + // mInitCheck will remain NO_INIT + return; + } + mFirstFramePos = pos; + mFixedHeader = header; + } size_t frame_size; int sample_rate; @@ -292,8 +327,6 @@ MP3Extractor::MP3Extractor( unsigned layer = 4 - ((header >> 17) & 3); - mMeta = new MetaData; - switch (layer) { case 1: mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I); @@ -312,27 +345,6 @@ MP3Extractor::MP3Extractor( mMeta->setInt32(kKeyBitRate, bitrate * 1000); mMeta->setInt32(kKeyChannelCount, num_channels); - sp<XINGSeeker> seeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos); - - if (seeker == NULL) { - mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos); - } else { - mSeeker = seeker; - int encd = seeker->getEncoderDelay(); - int encp = seeker->getEncoderPadding(); - if (encd != 0 || encp != 0) { - mMeta->setInt32(kKeyEncoderDelay, encd); - mMeta->setInt32(kKeyEncoderPadding, encp); - } - } - - if (mSeeker != NULL) { - // While it is safe to send the XING/VBRI frame to the decoder, this will - // result in an extra 1152 samples being output. The real first frame to - // decode is after the XING/VBRI frame, so skip there. - mFirstFramePos += frame_size; - } - int64_t durationUs; if (mSeeker == NULL || !mSeeker->getDuration(&durationUs)) { diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp index aa0d2e6..25887ef 100644 --- a/media/libstagefright/MediaCodec.cpp +++ b/media/libstagefright/MediaCodec.cpp @@ -42,7 +42,6 @@ #include <media/stagefright/MediaErrors.h> #include <media/stagefright/MediaFilter.h> #include <media/stagefright/MetaData.h> -#include <media/stagefright/NativeWindowWrapper.h> #include <private/android_filesystem_config.h> #include <utils/Log.h> #include <utils/Singleton.h> @@ -392,6 +391,10 @@ status_t MediaCodec::init(const AString &name, bool nameIsType, bool encoder) { tmp.erase(tmp.size() - 7, 7); } const sp<IMediaCodecList> mcl = MediaCodecList::getInstance(); + if (mcl == NULL) { + mCodec = NULL; // remove the codec. + return NO_INIT; // if called from Java should raise IOException + } ssize_t codecIdx = mcl->findCodecByName(tmp.c_str()); if (codecIdx >= 0) { const sp<MediaCodecInfo> info = mcl->getCodecInfo(codecIdx); @@ -477,9 +480,7 @@ status_t MediaCodec::configure( msg->setInt32("flags", flags); if (nativeWindow != NULL) { - msg->setObject( - "native-window", - new NativeWindowWrapper(nativeWindow)); + msg->setObject("native-window", nativeWindow); } if (crypto != NULL) { @@ -1610,11 +1611,7 @@ void MediaCodec::onMessageReceived(const sp<AMessage> &msg) { if (obj != NULL) { format->setObject("native-window", obj); - - status_t err = setNativeWindow( - static_cast<NativeWindowWrapper *>(obj.get()) - ->getSurfaceTextureClient()); - + status_t err = setNativeWindow(static_cast<Surface *>(obj.get())); if (err != OK) { PostReplyWithError(replyID, err); break; diff --git a/media/libstagefright/MediaCodecList.cpp b/media/libstagefright/MediaCodecList.cpp index 26798ae..f12a913 100644 --- a/media/libstagefright/MediaCodecList.cpp +++ b/media/libstagefright/MediaCodecList.cpp @@ -80,6 +80,10 @@ sp<IMediaCodecList> MediaCodecList::getLocalInstance() { infos.push_back(gCodecList->getCodecInfo(i)); } } + } else { + // failure to initialize may be temporary. retry on next call. + delete gCodecList; + gCodecList = NULL; } } } @@ -168,7 +172,7 @@ void MediaCodecList::parseTopLevelXMLFile(const char *codecs_xml, bool ignore_er OMXClient client; mInitCheck = client.connect(); if (mInitCheck != OK) { - return; + return; // this may fail if IMediaPlayerService is not available. } mOMX = client.interface(); parseXMLFile(codecs_xml); @@ -882,14 +886,16 @@ status_t MediaCodecList::addLimit(const char **attrs) { return -EINVAL; } - // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio: range + // size, blocks, bitrate, frame-rate, blocks-per-second, aspect-ratio, + // measured-frame-rate, measured-blocks-per-second: range // quality: range + default + [scale] // complexity: range + default bool found; if (name == "aspect-ratio" || name == "bitrate" || name == "block-count" || name == "blocks-per-second" || name == "complexity" - || name == "frame-rate" || name == "quality" || name == "size") { + || name == "frame-rate" || name == "quality" || name == "size" + || name == "measured-blocks-per-second" || name == "measured-frame-rate") { AString min, max; if (msg->findString("min", &min) && msg->findString("max", &max)) { min.append("-"); diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp index 8030a36..85027ce 100644 --- a/media/libstagefright/MediaSync.cpp +++ b/media/libstagefright/MediaSync.cpp @@ -56,6 +56,10 @@ MediaSync::MediaSync() mPlaybackRate(0.0) { mMediaClock = new MediaClock; + // initialize settings + mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT; + mPlaybackSettings.mSpeed = mPlaybackRate; + mLooper = new ALooper; mLooper->setName("MediaSync"); mLooper->start(false, false, ANDROID_PRIORITY_AUDIO); @@ -84,6 +88,11 @@ status_t MediaSync::configureSurface(const sp<IGraphicBufferProducer> &output) { return INVALID_OPERATION; } + if (output == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_VSYNC) { + ALOGE("configureSurface: output surface is used as sync source and cannot be removed."); + return INVALID_OPERATION; + } + if (output != NULL) { IGraphicBufferProducer::QueueBufferOutput queueBufferOutput; sp<OutputListener> listener(new OutputListener(this)); @@ -105,8 +114,7 @@ status_t MediaSync::configureSurface(const sp<IGraphicBufferProducer> &output) { } // |audioTrack| is used only for querying information. -status_t MediaSync::configureAudioTrack( - const sp<AudioTrack> &audioTrack, uint32_t nativeSampleRateInHz) { +status_t MediaSync::configureAudioTrack(const sp<AudioTrack> &audioTrack) { Mutex::Autolock lock(mMutex); // TODO: support audio track change. @@ -115,15 +123,35 @@ status_t MediaSync::configureAudioTrack( return INVALID_OPERATION; } - if (audioTrack != NULL && nativeSampleRateInHz <= 0) { - ALOGE("configureAudioTrack: native sample rate should be positive."); - return BAD_VALUE; + if (audioTrack == NULL && mSyncSettings.mSource == AVSYNC_SOURCE_AUDIO) { + ALOGE("configureAudioTrack: audioTrack is used as sync source and cannot be removed."); + return INVALID_OPERATION; } - mAudioTrack = audioTrack; - mNativeSampleRateInHz = nativeSampleRateInHz; + if (audioTrack != NULL) { + // check if audio track supports the playback settings + if (mPlaybackSettings.mSpeed != 0.f + && audioTrack->setPlaybackRate(mPlaybackSettings) != OK) { + ALOGE("playback settings are not supported by the audio track"); + return INVALID_OPERATION; + } + uint32_t nativeSampleRateInHz = audioTrack->getOriginalSampleRate(); + if (nativeSampleRateInHz <= 0) { + ALOGE("configureAudioTrack: native sample rate should be positive."); + return BAD_VALUE; + } + mAudioTrack = audioTrack; + mNativeSampleRateInHz = nativeSampleRateInHz; + (void)setPlaybackSettings_l(mPlaybackSettings); + } + else { + mAudioTrack = NULL; + mNativeSampleRateInHz = 0; + } - return NO_ERROR; + // potentially resync to new source + resync_l(); + return OK; } status_t MediaSync::createInputSurface( @@ -158,21 +186,27 @@ status_t MediaSync::createInputSurface( return status; } -status_t MediaSync::setPlaybackRate(float rate) { - if (rate < 0.0) { - return BAD_VALUE; +void MediaSync::resync_l() { + AVSyncSource src = mSyncSettings.mSource; + if (src == AVSYNC_SOURCE_DEFAULT) { + if (mAudioTrack != NULL) { + src = AVSYNC_SOURCE_AUDIO; + } else { + src = AVSYNC_SOURCE_SYSTEM_CLOCK; + } } - Mutex::Autolock lock(mMutex); + // TODO: resync ourselves to the current clock (e.g. on sync source change) + updatePlaybackRate_l(mPlaybackRate); +} +void MediaSync::updatePlaybackRate_l(float rate) { if (rate > mPlaybackRate) { mNextBufferItemMediaUs = -1; } mPlaybackRate = rate; mMediaClock->setPlaybackRate(rate); onDrainVideo_l(); - - return OK; } sp<const MediaClock> MediaSync::getMediaClock() { @@ -264,6 +298,95 @@ void MediaSync::setName(const AString &name) { mInput->setConsumerName(String8(name.c_str())); } +status_t MediaSync::setVideoFrameRateHint(float rate) { + // ignored until we add the FrameScheduler + return rate >= 0.f ? OK : BAD_VALUE; +} + +float MediaSync::getVideoFrameRate() { + // we don't know the frame rate + return -1.f; +} + +status_t MediaSync::setSyncSettings(const AVSyncSettings &syncSettings) { + // validate settings + if (syncSettings.mSource >= AVSYNC_SOURCE_MAX + || syncSettings.mAudioAdjustMode >= AVSYNC_AUDIO_ADJUST_MODE_MAX + || syncSettings.mTolerance < 0.f + || syncSettings.mTolerance >= AVSYNC_TOLERANCE_MAX) { + return BAD_VALUE; + } + + Mutex::Autolock lock(mMutex); + + // verify that we have the sync source + switch (syncSettings.mSource) { + case AVSYNC_SOURCE_AUDIO: + if (mAudioTrack == NULL) { + ALOGE("setSyncSettings: audio sync source requires an audio track"); + return BAD_VALUE; + } + break; + case AVSYNC_SOURCE_VSYNC: + if (mOutput == NULL) { + ALOGE("setSyncSettings: vsync sync source requires an output surface"); + return BAD_VALUE; + } + break; + default: + break; + } + + mSyncSettings = syncSettings; + resync_l(); + return OK; +} + +void MediaSync::getSyncSettings(AVSyncSettings *syncSettings) { + Mutex::Autolock lock(mMutex); + *syncSettings = mSyncSettings; +} + +status_t MediaSync::setPlaybackSettings(const AudioPlaybackRate &rate) { + Mutex::Autolock lock(mMutex); + + status_t err = setPlaybackSettings_l(rate); + if (err == OK) { + // TODO: adjust rate if using VSYNC as source + updatePlaybackRate_l(rate.mSpeed); + } + return err; +} + +status_t MediaSync::setPlaybackSettings_l(const AudioPlaybackRate &rate) { + if (rate.mSpeed < 0.f || rate.mPitch < 0.f) { + // We don't validate other audio settings. + // They will be validated when/if audiotrack is set. + return BAD_VALUE; + } + + if (mAudioTrack != NULL) { + if (rate.mSpeed == 0.f) { + mAudioTrack->pause(); + } else { + status_t err = mAudioTrack->setPlaybackRate(rate); + if (err != OK) { + return BAD_VALUE; + } + + // ignore errors + (void)mAudioTrack->start(); + } + } + mPlaybackSettings = rate; + return OK; +} + +void MediaSync::getPlaybackSettings(AudioPlaybackRate *rate) { + Mutex::Autolock lock(mMutex); + *rate = mPlaybackSettings; +} + int64_t MediaSync::getRealTime(int64_t mediaTimeUs, int64_t nowUs) { int64_t realUs; if (mMediaClock->getRealTimeFor(mediaTimeUs, &realUs) != OK) { @@ -430,7 +553,16 @@ void MediaSync::onFrameAvailableFromInput() { return; } + if (mBuffersFromInput.indexOfKey(bufferItem.mGraphicBuffer->getId()) >= 0) { + // Something is wrong since this buffer should be at our hands, bail. + mInput->consumerDisconnect(); + onAbandoned_l(true /* isInput */); + return; + } + mBuffersFromInput.add(bufferItem.mGraphicBuffer->getId(), bufferItem.mGraphicBuffer); + mBufferItems.push_back(bufferItem); + if (mBufferItems.size() == 1) { onDrainVideo_l(); } @@ -497,9 +629,19 @@ void MediaSync::onBufferReleasedByOutput() { void MediaSync::returnBufferToInput_l( const sp<GraphicBuffer> &buffer, const sp<Fence> &fence) { + ssize_t ix = mBuffersFromInput.indexOfKey(buffer->getId()); + if (ix < 0) { + // The buffer is unknown, something is wrong, bail. + mOutput->disconnect(NATIVE_WINDOW_API_MEDIA); + onAbandoned_l(false /* isInput */); + return; + } + sp<GraphicBuffer> oldBuffer = mBuffersFromInput.valueAt(ix); + mBuffersFromInput.removeItemsAt(ix); + // Attach and release the buffer back to the input. int consumerSlot; - status_t status = mInput->attachBuffer(&consumerSlot, buffer); + status_t status = mInput->attachBuffer(&consumerSlot, oldBuffer); ALOGE_IF(status != NO_ERROR, "attaching buffer to input failed (%d)", status); if (status == NO_ERROR) { status = mInput->releaseBuffer(consumerSlot, 0 /* frameNumber */, @@ -512,7 +654,7 @@ void MediaSync::returnBufferToInput_l( return; } - ALOGV("released buffer %#llx to input", (long long)buffer->getId()); + ALOGV("released buffer %#llx to input", (long long)oldBuffer->getId()); // Notify any waiting onFrameAvailable calls. --mNumOutstandingBuffers; diff --git a/media/libstagefright/OMXClient.cpp b/media/libstagefright/OMXClient.cpp index 230c1f7..06a598f 100644 --- a/media/libstagefright/OMXClient.cpp +++ b/media/libstagefright/OMXClient.cpp @@ -400,10 +400,16 @@ status_t OMXClient::connect() { sp<IBinder> binder = sm->getService(String16("media.player")); sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); - CHECK(service.get() != NULL); + if (service.get() == NULL) { + ALOGE("Cannot obtain IMediaPlayerService"); + return NO_INIT; + } mOMX = service->getOMX(); - CHECK(mOMX.get() != NULL); + if (mOMX.get() == NULL) { + ALOGE("Cannot obtain IOMX"); + return NO_INIT; + } if (!mOMX->livesLocally(0 /* node */, getpid())) { ALOGI("Using client-side OMX mux."); diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp index 0d8e64a..413628d 100644 --- a/media/libstagefright/Utils.cpp +++ b/media/libstagefright/Utils.cpp @@ -181,6 +181,11 @@ status_t convertMetaDataToMessage( msg->setInt32("rotation-degrees", rotationDegrees); } + int32_t fps; + if (meta->findInt32(kKeyFrameRate, &fps)) { + msg->setInt32("frame-rate", fps); + } + uint32_t type; const void *data; size_t size; @@ -588,6 +593,11 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) { meta->setInt32(kKeyMaxHeight, maxHeight); } + int32_t fps; + if (msg->findInt32("frame-rate", &fps)) { + meta->setInt32(kKeyFrameRate, fps); + } + // reassemble the csd data into its original form sp<ABuffer> csd0; if (msg->findBuffer("csd-0", &csd0)) { @@ -891,5 +901,39 @@ bool operator <(const HLSTime &t0, const HLSTime &t1) { || (t0.mSeq == t1.mSeq && t0.mTimeUs < t1.mTimeUs); } +void writeToAMessage(sp<AMessage> msg, const AudioPlaybackRate &rate) { + msg->setFloat("speed", rate.mSpeed); + msg->setFloat("pitch", rate.mPitch); + msg->setInt32("audio-fallback-mode", rate.mFallbackMode); + msg->setInt32("audio-stretch-mode", rate.mStretchMode); +} + +void readFromAMessage(const sp<AMessage> &msg, AudioPlaybackRate *rate /* nonnull */) { + *rate = AUDIO_PLAYBACK_RATE_DEFAULT; + CHECK(msg->findFloat("speed", &rate->mSpeed)); + CHECK(msg->findFloat("pitch", &rate->mPitch)); + CHECK(msg->findInt32("audio-fallback-mode", (int32_t *)&rate->mFallbackMode)); + CHECK(msg->findInt32("audio-stretch-mode", (int32_t *)&rate->mStretchMode)); +} + +void writeToAMessage(sp<AMessage> msg, const AVSyncSettings &sync, float videoFpsHint) { + msg->setInt32("sync-source", sync.mSource); + msg->setInt32("audio-adjust-mode", sync.mAudioAdjustMode); + msg->setFloat("tolerance", sync.mTolerance); + msg->setFloat("video-fps", videoFpsHint); +} + +void readFromAMessage( + const sp<AMessage> &msg, + AVSyncSettings *sync /* nonnull */, + float *videoFps /* nonnull */) { + AVSyncSettings settings; + CHECK(msg->findInt32("sync-source", (int32_t *)&settings.mSource)); + CHECK(msg->findInt32("audio-adjust-mode", (int32_t *)&settings.mAudioAdjustMode)); + CHECK(msg->findFloat("tolerance", &settings.mTolerance)); + CHECK(msg->findFloat("video-fps", videoFps)); + *sync = settings; +} + } // namespace android diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h index 8bba804..758b2c9 100644 --- a/media/libstagefright/include/AwesomePlayer.h +++ b/media/libstagefright/include/AwesomePlayer.h @@ -21,6 +21,7 @@ #include "HTTPBase.h" #include "TimedEventQueue.h" +#include <media/AudioResamplerPublic.h> #include <media/MediaPlayerInterface.h> #include <media/stagefright/DataSource.h> #include <media/stagefright/OMXClient.h> @@ -93,6 +94,8 @@ struct AwesomePlayer { status_t setParameter(int key, const Parcel &request); status_t getParameter(int key, Parcel *reply); + status_t setPlaybackSettings(const AudioPlaybackRate &rate); + status_t getPlaybackSettings(AudioPlaybackRate *rate /* nonnull */); status_t invoke(const Parcel &request, Parcel *reply); status_t setCacheStatCollectFreq(const Parcel &request); @@ -180,6 +183,7 @@ private: sp<MediaSource> mOmxSource; sp<MediaSource> mAudioSource; AudioPlayer *mAudioPlayer; + AudioPlaybackRate mPlaybackSettings; int64_t mDurationUs; int32_t mDisplayWidth; diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp index ddca437..70d2c69 100644 --- a/media/libstagefright/matroska/MatroskaExtractor.cpp +++ b/media/libstagefright/matroska/MatroskaExtractor.cpp @@ -925,6 +925,11 @@ void MatroskaExtractor::addTracks() { ALOGV("codec id = %s", codecID); ALOGV("codec name = %s", track->GetCodecNameAsUTF8()); + if (codecID == NULL) { + ALOGW("unknown codecID is not supported."); + continue; + } + size_t codecPrivateSize; const unsigned char *codecPrivate = track->GetCodecPrivate(codecPrivateSize); @@ -941,10 +946,7 @@ void MatroskaExtractor::addTracks() { const mkvparser::VideoTrack *vtrack = static_cast<const mkvparser::VideoTrack *>(track); - if (codecID == NULL) { - ALOGW("unknown codecID is not supported."); - continue; - } else if (!strcmp("V_MPEG4/ISO/AVC", codecID)) { + if (!strcmp("V_MPEG4/ISO/AVC", codecID)) { meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC); meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize); } else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) { diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp index 5411821..0d071b2 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.cpp +++ b/media/libstagefright/mpeg2ts/ATSParser.cpp @@ -302,9 +302,13 @@ bool ATSParser::Program::switchPIDs(const Vector<StreamInfo> &infos) { // The two checks below shouldn't happen, // we already checked above the stream count matches ssize_t index = newType2PIDs.indexOfKey(temp[i]->type()); - CHECK(index >= 0); + if (index < 0) { + return false; + } Vector<int32_t> &newPIDs = newType2PIDs.editValueAt(index); - CHECK(newPIDs.size() > 0); + if (newPIDs.isEmpty()) { + return false; + } // get the next PID for temp[i]->type() in the new PID map Vector<int32_t>::iterator it = newPIDs.begin(); @@ -335,13 +339,11 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) { return ERROR_MALFORMED; } - CHECK_EQ(br->getBits(1), 0u); + br->skipBits(1); // '0' MY_LOGV(" reserved = %u", br->getBits(2)); unsigned section_length = br->getBits(12); ALOGV(" section_length = %u", section_length); - CHECK_EQ(section_length & 0xc00, 0u); - CHECK_LE(section_length, 1021u); MY_LOGV(" program_number = %u", br->getBits(16)); MY_LOGV(" reserved = %u", br->getBits(2)); @@ -358,7 +360,6 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned program_info_length = br->getBits(12); ALOGV(" program_info_length = %u", program_info_length); - CHECK_EQ(program_info_length & 0xc00, 0u); br->skipBits(program_info_length * 8); // skip descriptors @@ -369,8 +370,7 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) { // final CRC. size_t infoBytesRemaining = section_length - 9 - program_info_length - 4; - while (infoBytesRemaining > 0) { - CHECK_GE(infoBytesRemaining, 5u); + while (infoBytesRemaining >= 5) { unsigned streamType = br->getBits(8); ALOGV(" stream_type = 0x%02x", streamType); @@ -384,9 +384,6 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned ES_info_length = br->getBits(12); ALOGV(" ES_info_length = %u", ES_info_length); - CHECK_EQ(ES_info_length & 0xc00, 0u); - - CHECK_GE(infoBytesRemaining - 5, ES_info_length); #if 0 br->skipBits(ES_info_length * 8); // skip descriptors @@ -398,13 +395,13 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) { unsigned descLength = br->getBits(8); ALOGV(" len = %u", descLength); - CHECK_GE(info_bytes_remaining, 2 + descLength); - + if (info_bytes_remaining < descLength) { + return ERROR_MALFORMED; + } br->skipBits(descLength * 8); info_bytes_remaining -= descLength + 2; } - CHECK_EQ(info_bytes_remaining, 0u); #endif StreamInfo info; @@ -415,7 +412,9 @@ status_t ATSParser::Program::parseProgramMap(ABitReader *br) { infoBytesRemaining -= 5 + ES_info_length; } - CHECK_EQ(infoBytesRemaining, 0u); + if (infoBytesRemaining != 0) { + ALOGW("Section data remains unconsumed"); + } MY_LOGV(" CRC = 0x%08x", br->getBits(32)); bool PIDsChanged = false; @@ -680,7 +679,10 @@ status_t ATSParser::Stream::parse( } size_t payloadSizeBits = br->numBitsLeft(); - CHECK_EQ(payloadSizeBits % 8, 0u); + if (payloadSizeBits % 8 != 0u) { + ALOGE("Wrong value"); + return BAD_VALUE; + } size_t neededSize = mBuffer->size() + payloadSizeBits / 8; if (mBuffer->capacity() < neededSize) { @@ -797,8 +799,6 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { return ERROR_MALFORMED; } - CHECK_EQ(packet_startcode_prefix, 0x000001u); - unsigned stream_id = br->getBits(8); ALOGV("stream_id = 0x%02x", stream_id); @@ -813,7 +813,9 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { && stream_id != 0xff // program_stream_directory && stream_id != 0xf2 // DSMCC && stream_id != 0xf8) { // H.222.1 type E - CHECK_EQ(br->getBits(2), 2u); + if (br->getBits(2) != 2u) { + return ERROR_MALFORMED; + } MY_LOGV("PES_scrambling_control = %u", br->getBits(2)); MY_LOGV("PES_priority = %u", br->getBits(1)); @@ -847,34 +849,51 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { uint64_t PTS = 0, DTS = 0; if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) { - CHECK_GE(optional_bytes_remaining, 5u); + if (optional_bytes_remaining < 5u) { + return ERROR_MALFORMED; + } if (br->getBits(4) != PTS_DTS_flags) { - ALOGE("PES data Error!"); return ERROR_MALFORMED; } PTS = ((uint64_t)br->getBits(3)) << 30; - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } PTS |= ((uint64_t)br->getBits(15)) << 15; - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } PTS |= br->getBits(15); - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } ALOGV("PTS = 0x%016" PRIx64 " (%.2f)", PTS, PTS / 90000.0); optional_bytes_remaining -= 5; if (PTS_DTS_flags == 3) { - CHECK_GE(optional_bytes_remaining, 5u); + if (optional_bytes_remaining < 5u) { + return ERROR_MALFORMED; + } - CHECK_EQ(br->getBits(4), 1u); + if (br->getBits(4) != 1u) { + return ERROR_MALFORMED; + } DTS = ((uint64_t)br->getBits(3)) << 30; - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } DTS |= ((uint64_t)br->getBits(15)) << 15; - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } DTS |= br->getBits(15); - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } ALOGV("DTS = %" PRIu64, DTS); @@ -883,31 +902,47 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { } if (ESCR_flag) { - CHECK_GE(optional_bytes_remaining, 6u); + if (optional_bytes_remaining < 6u) { + return ERROR_MALFORMED; + } br->getBits(2); uint64_t ESCR = ((uint64_t)br->getBits(3)) << 30; - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } ESCR |= ((uint64_t)br->getBits(15)) << 15; - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } ESCR |= br->getBits(15); - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } ALOGV("ESCR = %" PRIu64, ESCR); MY_LOGV("ESCR_extension = %u", br->getBits(9)); - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } optional_bytes_remaining -= 6; } if (ES_rate_flag) { - CHECK_GE(optional_bytes_remaining, 3u); + if (optional_bytes_remaining < 3u) { + return ERROR_MALFORMED; + } - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } MY_LOGV("ES_rate = %u", br->getBits(22)); - CHECK_EQ(br->getBits(1), 1u); + if (br->getBits(1) != 1u) { + return ERROR_MALFORMED; + } optional_bytes_remaining -= 3; } @@ -917,7 +952,9 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { // ES data follows. if (PES_packet_length != 0) { - CHECK_GE(PES_packet_length, PES_header_data_length + 3); + if (PES_packet_length < PES_header_data_length + 3) { + return ERROR_MALFORMED; + } unsigned dataLength = PES_packet_length - 3 - PES_header_data_length; @@ -930,7 +967,9 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { return ERROR_MALFORMED; } - CHECK_GE(br->numBitsLeft(), dataLength * 8); + if (br->numBitsLeft() < dataLength * 8) { + return ERROR_MALFORMED; + } onPayloadData( PTS_DTS_flags, PTS, DTS, br->data(), dataLength); @@ -942,15 +981,21 @@ status_t ATSParser::Stream::parsePES(ABitReader *br) { br->data(), br->numBitsLeft() / 8); size_t payloadSizeBits = br->numBitsLeft(); - CHECK_EQ(payloadSizeBits % 8, 0u); + if (payloadSizeBits % 8 != 0u) { + return ERROR_MALFORMED; + } ALOGV("There's %zu bytes of payload.", payloadSizeBits / 8); } } else if (stream_id == 0xbe) { // padding_stream - CHECK_NE(PES_packet_length, 0u); + if (PES_packet_length == 0u) { + return ERROR_MALFORMED; + } br->skipBits(PES_packet_length * 8); } else { - CHECK_NE(PES_packet_length, 0u); + if (PES_packet_length == 0u) { + return ERROR_MALFORMED; + } br->skipBits(PES_packet_length * 8); } @@ -1082,7 +1127,10 @@ ATSParser::~ATSParser() { } status_t ATSParser::feedTSPacket(const void *data, size_t size) { - CHECK_EQ(size, kTSPacketSize); + if (size != kTSPacketSize) { + ALOGE("Wrong TS packet size"); + return BAD_VALUE; + } ABitReader br((const uint8_t *)data, kTSPacketSize); return parseTS(&br); @@ -1108,14 +1156,23 @@ void ATSParser::signalDiscontinuity( } } else if (type == DISCONTINUITY_ABSOLUTE_TIME) { int64_t timeUs; - CHECK(extra->findInt64("timeUs", &timeUs)); + if (!extra->findInt64("timeUs", &timeUs)) { + ALOGE("timeUs not found"); + return; + } - CHECK(mPrograms.empty()); + if (!mPrograms.empty()) { + ALOGE("mPrograms is not empty"); + return; + } mAbsoluteTimeAnchorUs = timeUs; return; } else if (type == DISCONTINUITY_TIME_OFFSET) { int64_t offset; - CHECK(extra->findInt64("offset", &offset)); + if (!extra->findInt64("offset", &offset)) { + ALOGE("offset not found"); + return; + } mTimeOffsetValid = true; mTimeOffsetUs = offset; @@ -1128,7 +1185,10 @@ void ATSParser::signalDiscontinuity( } void ATSParser::signalEOS(status_t finalResult) { - CHECK_NE(finalResult, (status_t)OK); + if (finalResult == (status_t) OK) { + ALOGE("finalResult not OK"); + return; + } for (size_t i = 0; i < mPrograms.size(); ++i) { mPrograms.editItemAt(i)->signalEOS(finalResult); @@ -1144,14 +1204,12 @@ void ATSParser::parseProgramAssociationTable(ABitReader *br) { } unsigned section_syntax_indictor = br->getBits(1); ALOGV(" section_syntax_indictor = %u", section_syntax_indictor); - CHECK_EQ(section_syntax_indictor, 1u); - CHECK_EQ(br->getBits(1), 0u); + br->skipBits(1); // '0' MY_LOGV(" reserved = %u", br->getBits(2)); unsigned section_length = br->getBits(12); ALOGV(" section_length = %u", section_length); - CHECK_EQ(section_length & 0xc00, 0u); MY_LOGV(" transport_stream_id = %u", br->getBits(16)); MY_LOGV(" reserved = %u", br->getBits(2)); @@ -1161,7 +1219,6 @@ void ATSParser::parseProgramAssociationTable(ABitReader *br) { MY_LOGV(" last_section_number = %u", br->getBits(8)); size_t numProgramBytes = (section_length - 5 /* header */ - 4 /* crc */); - CHECK_EQ((numProgramBytes % 4), 0u); for (size_t i = 0; i < numProgramBytes / 4; ++i) { unsigned program_number = br->getBits(16); @@ -1221,7 +1278,9 @@ status_t ATSParser::parsePID( br->skipBits(skip * 8); } - CHECK((br->numBitsLeft() % 8) == 0); + if (br->numBitsLeft() % 8 != 0) { + return ERROR_MALFORMED; + } status_t err = section->append(br->data(), br->numBitsLeft() / 8); if (err != OK) { @@ -1291,7 +1350,7 @@ status_t ATSParser::parsePID( return OK; } -void ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) { +status_t ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) { unsigned adaptation_field_length = br->getBits(8); if (adaptation_field_length > 0) { @@ -1307,6 +1366,9 @@ void ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) { size_t numBitsRead = 4; if (PCR_flag) { + if (adaptation_field_length * 8 < 52) { + return ERROR_MALFORMED; + } br->skipBits(4); uint64_t PCR_base = br->getBits(32); PCR_base = (PCR_base << 1) | br->getBits(1); @@ -1337,10 +1399,9 @@ void ATSParser::parseAdaptationField(ABitReader *br, unsigned PID) { numBitsRead += 52; } - CHECK_GE(adaptation_field_length * 8, numBitsRead); - br->skipBits(adaptation_field_length * 8 - numBitsRead); } + return OK; } status_t ATSParser::parseTS(ABitReader *br) { @@ -1375,15 +1436,16 @@ status_t ATSParser::parseTS(ABitReader *br) { // ALOGI("PID = 0x%04x, continuity_counter = %u", PID, continuity_counter); - if (adaptation_field_control == 2 || adaptation_field_control == 3) { - parseAdaptationField(br, PID); - } - status_t err = OK; - if (adaptation_field_control == 1 || adaptation_field_control == 3) { - err = parsePID( - br, PID, continuity_counter, payload_unit_start_indicator); + if (adaptation_field_control == 2 || adaptation_field_control == 3) { + err = parseAdaptationField(br, PID); + } + if (err == OK) { + if (adaptation_field_control == 1 || adaptation_field_control == 3) { + err = parsePID( + br, PID, continuity_counter, payload_unit_start_indicator); + } } ++mNumTSPacketsParsed; diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h index 87ab1a0..4def333 100644 --- a/media/libstagefright/mpeg2ts/ATSParser.h +++ b/media/libstagefright/mpeg2ts/ATSParser.h @@ -133,7 +133,7 @@ private: unsigned continuity_counter, unsigned payload_unit_start_indicator); - void parseAdaptationField(ABitReader *br, unsigned PID); + status_t parseAdaptationField(ABitReader *br, unsigned PID); status_t parseTS(ABitReader *br); void updatePCR(unsigned PID, uint64_t PCR, size_t byteOffsetFromStart); diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp index f28a1fd..7b5b46a 100644 --- a/media/libstagefright/mpeg2ts/ESQueue.cpp +++ b/media/libstagefright/mpeg2ts/ESQueue.cpp @@ -421,8 +421,8 @@ status_t ElementaryStreamQueue::appendData( } default: - TRESPASS(); - break; + ALOGE("Unknown mode: %d", mMode); + return ERROR_MALFORMED; } } @@ -503,7 +503,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() { case METADATA: return dequeueAccessUnitMetadata(); default: - CHECK_EQ((unsigned)mMode, (unsigned)MPEG_AUDIO); + if (mMode != MPEG_AUDIO) { + ALOGE("Unknown mode"); + return NULL; + } return dequeueAccessUnitMPEGAudio(); } } @@ -540,7 +543,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() { memcpy(accessUnit->data(), mBuffer->data(), syncStartPos + payloadSize); int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize); - CHECK_GE(timeUs, 0ll); + if (timeUs < 0ll) { + ALOGE("negative timeUs"); + return NULL; + } accessUnit->meta()->setInt64("timeUs", timeUs); accessUnit->meta()->setInt32("isSync", 1); @@ -560,15 +566,24 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() { } ABitReader bits(mBuffer->data(), 4); - CHECK_EQ(bits.getBits(8), 0xa0); + if (bits.getBits(8) != 0xa0) { + ALOGE("Unexpected bit values"); + return NULL; + } unsigned numAUs = bits.getBits(8); bits.skipBits(8); unsigned quantization_word_length __unused = bits.getBits(2); unsigned audio_sampling_frequency = bits.getBits(3); unsigned num_channels = bits.getBits(3); - CHECK_EQ(audio_sampling_frequency, 2); // 48kHz - CHECK_EQ(num_channels, 1u); // stereo! + if (audio_sampling_frequency != 2) { + ALOGE("Wrong sampling freq"); + return NULL; + } + if (num_channels != 1u) { + ALOGE("Wrong channel #"); + return NULL; + } if (mFormat == NULL) { mFormat = new MetaData; @@ -590,7 +605,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitPCMAudio() { memcpy(accessUnit->data(), mBuffer->data() + 4, payloadSize); int64_t timeUs = fetchTimestamp(payloadSize + 4); - CHECK_GE(timeUs, 0ll); + if (timeUs < 0ll) { + ALOGE("Negative timeUs"); + return NULL; + } accessUnit->meta()->setInt64("timeUs", timeUs); accessUnit->meta()->setInt32("isSync", 1); @@ -614,14 +632,19 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() { return NULL; } - CHECK(!mRangeInfos.empty()); + if (mRangeInfos.empty()) { + return NULL; + } const RangeInfo &info = *mRangeInfos.begin(); if (mBuffer->size() < info.mLength) { return NULL; } - CHECK_GE(info.mTimestampUs, 0ll); + if (info.mTimestampUs < 0ll) { + ALOGE("Negative info.mTimestampUs"); + return NULL; + } // The idea here is consume all AAC frames starting at offsets before // info.mLength so we can assign a meaningful timestamp without @@ -638,17 +661,26 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() { // adts_fixed_header - CHECK_EQ(bits.getBits(12), 0xfffu); + if (bits.getBits(12) != 0xfffu) { + ALOGE("Wrong atds_fixed_header"); + return NULL; + } bits.skipBits(3); // ID, layer bool protection_absent __unused = bits.getBits(1) != 0; if (mFormat == NULL) { unsigned profile = bits.getBits(2); - CHECK_NE(profile, 3u); + if (profile == 3u) { + ALOGE("profile should not be 3"); + return NULL; + } unsigned sampling_freq_index = bits.getBits(4); bits.getBits(1); // private_bit unsigned channel_configuration = bits.getBits(3); - CHECK_NE(channel_configuration, 0u); + if (channel_configuration == 0u) { + ALOGE("channel_config should not be 0"); + return NULL; + } bits.skipBits(2); // original_copy, home mFormat = MakeAACCodecSpecificData( @@ -658,8 +690,14 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() { int32_t sampleRate; int32_t numChannels; - CHECK(mFormat->findInt32(kKeySampleRate, &sampleRate)); - CHECK(mFormat->findInt32(kKeyChannelCount, &numChannels)); + if (!mFormat->findInt32(kKeySampleRate, &sampleRate)) { + ALOGE("SampleRate not found"); + return NULL; + } + if (!mFormat->findInt32(kKeyChannelCount, &numChannels)) { + ALOGE("ChannelCount not found"); + return NULL; + } ALOGI("found AAC codec config (%d Hz, %d channels)", sampleRate, numChannels); @@ -682,7 +720,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAAC() { if (number_of_raw_data_blocks_in_frame != 0) { // To be implemented. - TRESPASS(); + ALOGE("Should not reach here."); + return NULL; } if (offset + aac_frame_length > mBuffer->size()) { @@ -714,7 +753,9 @@ int64_t ElementaryStreamQueue::fetchTimestamp(size_t size) { bool first = true; while (size > 0) { - CHECK(!mRangeInfos.empty()); + if (mRangeInfos.empty()) { + return timeUs; + } RangeInfo *info = &*mRangeInfos.begin(); @@ -813,7 +854,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { unsigned nalType = mBuffer->data()[pos.nalOffset] & 0x1f; if (nalType == 6 && pos.nalSize > 0) { - CHECK_LT(seiIndex, sei->size() / sizeof(NALPosition)); + if (seiIndex >= sei->size() / sizeof(NALPosition)) { + ALOGE("Wrong seiIndex"); + return NULL; + } NALPosition &seiPos = ((NALPosition *)sei->data())[seiIndex++]; seiPos.nalOffset = dstOffset + 4; seiPos.nalSize = pos.nalSize; @@ -851,7 +895,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { mBuffer->setRange(0, mBuffer->size() - nextScan); int64_t timeUs = fetchTimestamp(nextScan); - CHECK_GE(timeUs, 0ll); + if (timeUs < 0ll) { + ALOGE("Negative timeUs"); + return NULL; + } accessUnit->meta()->setInt64("timeUs", timeUs); if (foundIDR) { @@ -873,7 +920,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() { totalSize += nalSize; } - CHECK_EQ(err, (status_t)-EAGAIN); + if (err != (status_t)-EAGAIN) { + ALOGE("Unexpeted err"); + return NULL; + } return NULL; } @@ -890,9 +940,12 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { size_t frameSize; int samplingRate, numChannels, bitrate, numSamples; - CHECK(GetMPEGAudioFrameSize( + if (!GetMPEGAudioFrameSize( header, &frameSize, &samplingRate, &numChannels, - &bitrate, &numSamples)); + &bitrate, &numSamples)) { + ALOGE("Failed to get audio frame size"); + return NULL; + } if (size < frameSize) { return NULL; @@ -910,7 +963,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { mBuffer->setRange(0, mBuffer->size() - frameSize); int64_t timeUs = fetchTimestamp(frameSize); - CHECK_GE(timeUs, 0ll); + if (timeUs < 0ll) { + ALOGE("Negative timeUs"); + return NULL; + } accessUnit->meta()->setInt64("timeUs", timeUs); accessUnit->meta()->setInt32("isSync", 1); @@ -932,7 +988,7 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG); break; default: - TRESPASS(); + return NULL; } mFormat->setInt32(kKeySampleRate, samplingRate); @@ -943,7 +999,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGAudio() { } static void EncodeSize14(uint8_t **_ptr, size_t size) { - CHECK_LE(size, 0x3fff); + if (size > 0x3fff) { + ALOGE("Wrong size"); + return; + } uint8_t *ptr = *_ptr; @@ -1018,7 +1077,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { // seqHeader without/with extension if (mFormat == NULL) { - CHECK_GE(size, 7u); + if (size < 7u) { + ALOGE("Size too small"); + return NULL; + } unsigned width = (data[4] << 4) | data[5] >> 4; @@ -1078,7 +1140,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() { mBuffer->setRange(0, mBuffer->size() - offset); int64_t timeUs = fetchTimestamp(offset); - CHECK_GE(timeUs, 0ll); + if (timeUs < 0ll) { + ALOGE("Negative timeUs"); + return NULL; + } offset = 0; @@ -1111,7 +1176,7 @@ static ssize_t getNextChunkSize( } if (memcmp(kStartCode, data, 3)) { - TRESPASS(); + return -EAGAIN; } size_t offset = 3; @@ -1171,25 +1236,37 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { case EXPECT_VISUAL_OBJECT_START: { - CHECK_EQ(chunkType, 0xb5); + if (chunkType != 0xb5) { + ALOGE("Unexpected chunkType"); + return NULL; + } state = EXPECT_VO_START; break; } case EXPECT_VO_START: { - CHECK_LE(chunkType, 0x1f); + if (chunkType > 0x1f) { + ALOGE("Unexpected chunkType"); + return NULL; + } state = EXPECT_VOL_START; break; } case EXPECT_VOL_START: { - CHECK((chunkType & 0xf0) == 0x20); + if ((chunkType & 0xf0) != 0x20) { + ALOGE("Wrong chunkType"); + return NULL; + } - CHECK(ExtractDimensionsFromVOLHeader( + if (!ExtractDimensionsFromVOLHeader( &data[offset], chunkSize, - &width, &height)); + &width, &height)) { + ALOGE("Failed to get dimension"); + return NULL; + } state = WAIT_FOR_VOP_START; break; @@ -1242,7 +1319,10 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { mBuffer->setRange(0, size); int64_t timeUs = fetchTimestamp(offset); - CHECK_GE(timeUs, 0ll); + if (timeUs < 0ll) { + ALOGE("Negative timeus"); + return NULL; + } offset = 0; @@ -1266,7 +1346,8 @@ sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEG4Video() { } default: - TRESPASS(); + ALOGE("Unknown state: %d", state); + return NULL; } if (discard) { diff --git a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp index 85859f7..6d9fe9d 100644 --- a/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2PSExtractor.cpp @@ -265,7 +265,10 @@ ssize_t MPEG2PSExtractor::dequeuePES() { } unsigned PES_packet_length = U16_AT(mBuffer->data() + 4); - CHECK_NE(PES_packet_length, 0u); + if (PES_packet_length == 0u) { + ALOGE("PES_packet_length is 0"); + return -EAGAIN; + } size_t n = PES_packet_length + 6; @@ -286,7 +289,10 @@ ssize_t MPEG2PSExtractor::dequeuePES() { return ERROR_MALFORMED; } - CHECK_EQ(packet_startcode_prefix, 0x000001u); + if (packet_startcode_prefix != 0x000001u) { + ALOGE("Wrong PES prefix"); + return ERROR_MALFORMED; + } unsigned stream_id = br.getBits(8); ALOGV("stream_id = 0x%02x", stream_id); @@ -366,8 +372,7 @@ ssize_t MPEG2PSExtractor::dequeuePES() { && stream_id != 0xff // program_stream_directory && stream_id != 0xf2 // DSMCC && stream_id != 0xf8) { // H.222.1 type E - CHECK_EQ(br.getBits(2), 2u); - + /* unsigned PES_marker_bits = */br.getBits(2); // should be 0x2(hex) /* unsigned PES_scrambling_control = */br.getBits(2); /* unsigned PES_priority = */br.getBits(1); /* unsigned data_alignment_indicator = */br.getBits(1); @@ -400,16 +405,26 @@ ssize_t MPEG2PSExtractor::dequeuePES() { uint64_t PTS = 0, DTS = 0; if (PTS_DTS_flags == 2 || PTS_DTS_flags == 3) { - CHECK_GE(optional_bytes_remaining, 5u); + if (optional_bytes_remaining < 5u) { + return ERROR_MALFORMED; + } - CHECK_EQ(br.getBits(4), PTS_DTS_flags); + if (br.getBits(4) != PTS_DTS_flags) { + return ERROR_MALFORMED; + } PTS = ((uint64_t)br.getBits(3)) << 30; - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } PTS |= ((uint64_t)br.getBits(15)) << 15; - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } PTS |= br.getBits(15); - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } ALOGV("PTS = %" PRIu64, PTS); // ALOGI("PTS = %.2f secs", PTS / 90000.0f); @@ -417,16 +432,26 @@ ssize_t MPEG2PSExtractor::dequeuePES() { optional_bytes_remaining -= 5; if (PTS_DTS_flags == 3) { - CHECK_GE(optional_bytes_remaining, 5u); + if (optional_bytes_remaining < 5u) { + return ERROR_MALFORMED; + } - CHECK_EQ(br.getBits(4), 1u); + if (br.getBits(4) != 1u) { + return ERROR_MALFORMED; + } DTS = ((uint64_t)br.getBits(3)) << 30; - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } DTS |= ((uint64_t)br.getBits(15)) << 15; - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } DTS |= br.getBits(15); - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } ALOGV("DTS = %" PRIu64, DTS); @@ -435,40 +460,62 @@ ssize_t MPEG2PSExtractor::dequeuePES() { } if (ESCR_flag) { - CHECK_GE(optional_bytes_remaining, 6u); + if (optional_bytes_remaining < 6u) { + return ERROR_MALFORMED; + } br.getBits(2); uint64_t ESCR = ((uint64_t)br.getBits(3)) << 30; - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } ESCR |= ((uint64_t)br.getBits(15)) << 15; - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } ESCR |= br.getBits(15); - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } ALOGV("ESCR = %" PRIu64, ESCR); /* unsigned ESCR_extension = */br.getBits(9); - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } optional_bytes_remaining -= 6; } if (ES_rate_flag) { - CHECK_GE(optional_bytes_remaining, 3u); + if (optional_bytes_remaining < 3u) { + return ERROR_MALFORMED; + } - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } /* unsigned ES_rate = */br.getBits(22); - CHECK_EQ(br.getBits(1), 1u); + if (br.getBits(1) != 1u) { + return ERROR_MALFORMED; + } optional_bytes_remaining -= 3; } + if (br.numBitsLeft() < optional_bytes_remaining * 8) { + return ERROR_MALFORMED; + } + br.skipBits(optional_bytes_remaining * 8); // ES data follows. - CHECK_GE(PES_packet_length, PES_header_data_length + 3); + if (PES_packet_length < PES_header_data_length + 3) { + return ERROR_MALFORMED; + } unsigned dataLength = PES_packet_length - 3 - PES_header_data_length; @@ -481,7 +528,9 @@ ssize_t MPEG2PSExtractor::dequeuePES() { return ERROR_MALFORMED; } - CHECK_GE(br.numBitsLeft(), dataLength * 8); + if (br.numBitsLeft() < dataLength * 8) { + return ERROR_MALFORMED; + } ssize_t index = mTracks.indexOfKey(stream_id); if (index < 0 && mScanning) { @@ -521,10 +570,14 @@ ssize_t MPEG2PSExtractor::dequeuePES() { return err; } } else if (stream_id == 0xbe) { // padding_stream - CHECK_NE(PES_packet_length, 0u); + if (PES_packet_length == 0u) { + return ERROR_MALFORMED; + } br.skipBits(PES_packet_length * 8); } else { - CHECK_NE(PES_packet_length, 0u); + if (PES_packet_length == 0u) { + return ERROR_MALFORMED; + } br.skipBits(PES_packet_length * 8); } diff --git a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp index 74cb5d8..f5c33cf 100644 --- a/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp +++ b/media/libstagefright/mpeg2ts/MPEG2TSExtractor.cpp @@ -131,7 +131,10 @@ sp<MediaSource> MPEG2TSExtractor::getTrack(size_t index) { bool seekable = true; if (mSourceImpls.size() > 1) { - CHECK_EQ(mSourceImpls.size(), 2u); + if (mSourceImpls.size() != 2u) { + ALOGE("Wrong size"); + return NULL; + } sp<MetaData> meta = mSourceImpls.editItemAt(index)->getFormat(); const char *mime; diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index fd889f9..3860e9b 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -19,6 +19,7 @@ #include <gtest/gtest.h> #include <utils/String8.h> +#include <utils/String16.h> #include <utils/Errors.h> #include <fcntl.h> #include <unistd.h> @@ -466,7 +467,7 @@ void SurfaceMediaSourceGLTest::oneBufferPassGL(int num) { // Set up the MediaRecorder which runs in the same process as mediaserver sp<MediaRecorder> SurfaceMediaSourceGLTest::setUpMediaRecorder(int fd, int videoSource, int outputFormat, int videoEncoder, int width, int height, int fps) { - sp<MediaRecorder> mr = new MediaRecorder(); + sp<MediaRecorder> mr = new MediaRecorder(String16()); mr->setVideoSource(videoSource); mr->setOutputFormat(outputFormat); mr->setVideoEncoder(videoEncoder); diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp index 5e2f0bf..ed5a404 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp +++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp @@ -345,12 +345,14 @@ bool WifiDisplaySource::PlaybackSession::Track::isSuspended() const { //////////////////////////////////////////////////////////////////////////////// WifiDisplaySource::PlaybackSession::PlaybackSession( + const String16 &opPackageName, const sp<ANetworkSession> &netSession, const sp<AMessage> ¬ify, const in_addr &interfaceAddr, const sp<IHDCP> &hdcp, const char *path) - : mNetSession(netSession), + : mOpPackageName(opPackageName), + mNetSession(netSession), mNotify(notify), mInterfaceAddr(interfaceAddr), mHDCP(hdcp), @@ -1069,6 +1071,7 @@ status_t WifiDisplaySource::PlaybackSession::addVideoSource( status_t WifiDisplaySource::PlaybackSession::addAudioSource(bool usePCMAudio) { sp<AudioSource> audioSource = new AudioSource( AUDIO_SOURCE_REMOTE_SUBMIX, + mOpPackageName, 48000 /* sampleRate */, 2 /* channelCount */); diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h index 4cd1a75..f6673df 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.h +++ b/media/libstagefright/wifi-display/source/PlaybackSession.h @@ -22,6 +22,8 @@ #include "VideoFormats.h" #include "WifiDisplaySource.h" +#include <utils/String16.h> + namespace android { struct ABuffer; @@ -36,6 +38,7 @@ struct NuMediaExtractor; // display. struct WifiDisplaySource::PlaybackSession : public AHandler { PlaybackSession( + const String16 &opPackageName, const sp<ANetworkSession> &netSession, const sp<AMessage> ¬ify, const struct in_addr &interfaceAddr, @@ -96,6 +99,8 @@ private: kWhatPullExtractorSample, }; + String16 mOpPackageName; + sp<ANetworkSession> mNetSession; sp<AMessage> mNotify; in_addr mInterfaceAddr; diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp index 332fe16..e26165e 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp @@ -50,10 +50,12 @@ const int64_t WifiDisplaySource::kPlaybackSessionTimeoutUs; const AString WifiDisplaySource::sUserAgent = MakeUserAgent(); WifiDisplaySource::WifiDisplaySource( + const String16 &opPackageName, const sp<ANetworkSession> &netSession, const sp<IRemoteDisplayClient> &client, const char *path) - : mState(INITIALIZED), + : mOpPackageName(opPackageName), + mState(INITIALIZED), mNetSession(netSession), mClient(client), mSessionID(0), @@ -1245,7 +1247,7 @@ status_t WifiDisplaySource::onSetupRequest( sp<PlaybackSession> playbackSession = new PlaybackSession( - mNetSession, notify, mInterfaceAddr, mHDCP, mMediaPath.c_str()); + mOpPackageName, mNetSession, notify, mInterfaceAddr, mHDCP, mMediaPath.c_str()); looper()->registerHandler(playbackSession); diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h index c417cf5..c25a675 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h @@ -25,6 +25,8 @@ #include <netinet/in.h> +#include <utils/String16.h> + namespace android { struct AReplyToken; @@ -38,6 +40,7 @@ struct WifiDisplaySource : public AHandler { static const unsigned kWifiDisplayDefaultPort = 7236; WifiDisplaySource( + const String16 &opPackageName, const sp<ANetworkSession> &netSession, const sp<IRemoteDisplayClient> &client, const char *path = NULL); @@ -114,6 +117,8 @@ private: static const AString sUserAgent; + String16 mOpPackageName; + State mState; VideoFormats mSupportedSourceVideoFormats; sp<ANetworkSession> mNetSession; diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 80c1c2f..cd0c462 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -154,6 +154,10 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool } else { mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); } + if (mData->mCodec == NULL) { // failed to create codec + AMediaCodec_delete(mData); + return NULL; + } mData->mHandler = new CodecHandler(mData); mData->mLooper->registerHandler(mData->mHandler); mData->mGeneration = 1; @@ -180,17 +184,21 @@ AMediaCodec* AMediaCodec_createEncoderByType(const char *name) { EXPORT media_status_t AMediaCodec_delete(AMediaCodec *mData) { - if (mData->mCodec != NULL) { - mData->mCodec->release(); - mData->mCodec.clear(); - } + if (mData != NULL) { + if (mData->mCodec != NULL) { + mData->mCodec->release(); + mData->mCodec.clear(); + } - if (mData->mLooper != NULL) { - mData->mLooper->unregisterHandler(mData->mHandler->id()); - mData->mLooper->stop(); - mData->mLooper.clear(); + if (mData->mLooper != NULL) { + if (mData->mHandler != NULL) { + mData->mLooper->unregisterHandler(mData->mHandler->id()); + } + mData->mLooper->stop(); + mData->mLooper.clear(); + } + delete mData; } - delete mData; return AMEDIA_OK; } diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index 3e4b1fc..bd6889d 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1421,6 +1421,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, + const String16& opPackageName, size_t *frameCount, IAudioFlinger::track_flags_t *flags, pid_t tid, @@ -1440,7 +1441,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( buffers.clear(); // check calling permissions - if (!recordingAllowed()) { + if (!recordingAllowed(opPackageName)) { ALOGE("openRecord() permission denied: recording not allowed"); lStatus = PERMISSION_DENIED; goto Exit; @@ -2456,6 +2457,7 @@ sp<IEffect> AudioFlinger::createEffect( int32_t priority, audio_io_handle_t io, int sessionId, + const String16& opPackageName, status_t *status, int *id, int *enabled) @@ -2552,7 +2554,7 @@ sp<IEffect> AudioFlinger::createEffect( // check recording permission for visualizer if ((memcmp(&desc.type, SL_IID_VISUALIZATION, sizeof(effect_uuid_t)) == 0) && - !recordingAllowed()) { + !recordingAllowed(opPackageName)) { lStatus = PERMISSION_DENIED; goto Exit; } diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 8e06138..8085ec2 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -120,6 +120,7 @@ public: uint32_t sampleRate, audio_format_t format, audio_channel_mask_t channelMask, + const String16& opPackageName, size_t *pFrameCount, IAudioFlinger::track_flags_t *flags, pid_t tid, @@ -216,6 +217,7 @@ public: int32_t priority, audio_io_handle_t io, int sessionId, + const String16& opPackageName, status_t *status /*non-NULL*/, int *id, int *enabled); diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index c51021b..7bc6f0c 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -156,11 +156,6 @@ private: bool mResumeToStopping; // track was paused in stopping state. bool mFlushHwPending; // track requests for thread flush - // for last call to getTimestamp - bool mPreviousTimestampValid; - // This is either the first timestamp or one that has passed - // the check to prevent retrograde motion. - AudioTimestamp mPreviousTimestamp; }; // end of Track class TimedTrack : public Track { diff --git a/services/audioflinger/ServiceUtilities.cpp b/services/audioflinger/ServiceUtilities.cpp index 8246fef..0a718fb 100644 --- a/services/audioflinger/ServiceUtilities.cpp +++ b/services/audioflinger/ServiceUtilities.cpp @@ -14,38 +14,97 @@ * limitations under the License. */ +#include <binder/AppOpsManager.h> #include <binder/IPCThreadState.h> #include <binder/IServiceManager.h> #include <binder/PermissionCache.h> #include "ServiceUtilities.h" +/* When performing permission checks we do not use permission cache for + * runtime permissions (protection level dangerous) as they may change at + * runtime. All other permissions (protection level normal and dangerous) + * can be cached as they never change. Of course all permission checked + * here are platform defined. + */ + namespace android { // Not valid until initialized by AudioFlinger constructor. It would have to be // re-initialized if the process containing AudioFlinger service forks (which it doesn't). pid_t getpid_cached; -bool recordingAllowed() { +bool recordingAllowed(const String16& opPackageName) { + // Note: We are getting the UID from the calling IPC thread state because all + // clients that perform recording create AudioRecord in their own processes + // and the system does not create AudioRecord objects on behalf of apps. This + // differs from playback where in some situations the system recreates AudioTrack + // instances associated with a client's MediaPlayer on behalf of this client. + // In the latter case we have to store the client UID and pass in along for + // security checks. + if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true; static const String16 sRecordAudio("android.permission.RECORD_AUDIO"); - // don't use PermissionCache; this is not a system permission - bool ok = checkCallingPermission(sRecordAudio); - if (!ok) ALOGE("Request requires android.permission.RECORD_AUDIO"); - return ok; + + // IMPORTANT: Don't use PermissionCache - a runtime permission and may change. + const bool ok = checkCallingPermission(sRecordAudio); + if (!ok) { + ALOGE("Request requires android.permission.RECORD_AUDIO"); + return false; + } + + const uid_t uid = IPCThreadState::self()->getCallingUid(); + String16 checkedOpPackageName = opPackageName; + + // In some cases the calling code has no access to the package it runs under. + // For example, code using the wilhelm framework's OpenSL-ES APIs. In this + // case we will get the packages for the calling UID and pick the first one + // for attributing the app op. This will work correctly for runtime permissions + // as for legacy apps we will toggle the app op for all packages in the UID. + // The caveat is that the operation may be attributed to the wrong package and + // stats based on app ops may be slightly off. + if (checkedOpPackageName.size() <= 0) { + sp<IServiceManager> sm = defaultServiceManager(); + sp<IBinder> binder = sm->getService(String16("permission")); + if (binder == 0) { + ALOGE("Cannot get permission service"); + return false; + } + + sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder); + Vector<String16> packages; + + permCtrl->getPackagesForUid(uid, packages); + + if (packages.isEmpty()) { + ALOGE("No packages for calling UID"); + return false; + } + checkedOpPackageName = packages[0]; + } + + AppOpsManager appOps; + if (appOps.noteOp(AppOpsManager::OP_RECORD_AUDIO, uid, opPackageName) + != AppOpsManager::MODE_ALLOWED) { + ALOGE("Request denied by app op OP_RECORD_AUDIO"); + return false; + } + + return true; } bool captureAudioOutputAllowed() { if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true; static const String16 sCaptureAudioOutput("android.permission.CAPTURE_AUDIO_OUTPUT"); - // don't use PermissionCache; this is not a system permission - bool ok = checkCallingPermission(sCaptureAudioOutput); + // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. + bool ok = PermissionCache::checkCallingPermission(sCaptureAudioOutput); if (!ok) ALOGE("Request requires android.permission.CAPTURE_AUDIO_OUTPUT"); return ok; } bool captureHotwordAllowed() { static const String16 sCaptureHotwordAllowed("android.permission.CAPTURE_AUDIO_HOTWORD"); - bool ok = checkCallingPermission(sCaptureHotwordAllowed); + // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. + bool ok = PermissionCache::checkCallingPermission(sCaptureHotwordAllowed); if (!ok) ALOGE("android.permission.CAPTURE_AUDIO_HOTWORD"); return ok; } @@ -53,15 +112,16 @@ bool captureHotwordAllowed() { bool settingsAllowed() { if (getpid_cached == IPCThreadState::self()->getCallingPid()) return true; static const String16 sAudioSettings("android.permission.MODIFY_AUDIO_SETTINGS"); - // don't use PermissionCache; this is not a system permission - bool ok = checkCallingPermission(sAudioSettings); + // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. + bool ok = PermissionCache::checkCallingPermission(sAudioSettings); if (!ok) ALOGE("Request requires android.permission.MODIFY_AUDIO_SETTINGS"); return ok; } bool modifyAudioRoutingAllowed() { static const String16 sModifyAudioRoutingAllowed("android.permission.MODIFY_AUDIO_ROUTING"); - bool ok = checkCallingPermission(sModifyAudioRoutingAllowed); + // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. + bool ok = PermissionCache::checkCallingPermission(sModifyAudioRoutingAllowed); if (!ok) ALOGE("android.permission.MODIFY_AUDIO_ROUTING"); return ok; } @@ -69,7 +129,7 @@ bool modifyAudioRoutingAllowed() { bool dumpAllowed() { // don't optimize for same pid, since mediaserver never dumps itself static const String16 sDump("android.permission.DUMP"); - // OK to use PermissionCache; this is a system permission + // IMPORTANT: Use PermissionCache - not a runtime permission and may not change. bool ok = PermissionCache::checkCallingPermission(sDump); // convention is for caller to dump an error message to fd instead of logging here //if (!ok) ALOGE("Request requires android.permission.DUMP"); diff --git a/services/audioflinger/ServiceUtilities.h b/services/audioflinger/ServiceUtilities.h index df6f6f4..fba6dce 100644 --- a/services/audioflinger/ServiceUtilities.h +++ b/services/audioflinger/ServiceUtilities.h @@ -20,11 +20,10 @@ namespace android { extern pid_t getpid_cached; -bool recordingAllowed(); +bool recordingAllowed(const String16& opPackageName); bool captureAudioOutputAllowed(); bool captureHotwordAllowed(); bool settingsAllowed(); bool modifyAudioRoutingAllowed(); bool dumpAllowed(); - } diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index c6e9745..1b03060 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -404,8 +404,7 @@ AudioFlinger::PlaybackThread::Track::Track( mIsInvalid(false), mAudioTrackServerProxy(NULL), mResumeToStopping(false), - mFlushHwPending(false), - mPreviousTimestampValid(false) + mFlushHwPending(false) { // client == 0 implies sharedBuffer == 0 ALOG_ASSERT(!(client == 0 && sharedBuffer != 0)); @@ -863,7 +862,6 @@ void AudioFlinger::PlaybackThread::Track::reset() if (mState == FLUSHED) { mState = IDLE; } - mPreviousTimestampValid = false; } } @@ -885,12 +883,10 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times { // Client should implement this using SSQ; the unpresented frame count in latch is irrelevant if (isFastTrack()) { - // FIXME no lock held to set mPreviousTimestampValid = false return INVALID_OPERATION; } sp<ThreadBase> thread = mThread.promote(); if (thread == 0) { - // FIXME no lock held to set mPreviousTimestampValid = false return INVALID_OPERATION; } @@ -900,7 +896,6 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times status_t result = INVALID_OPERATION; if (!isOffloaded() && !isDirect()) { if (!playbackThread->mLatchQValid) { - mPreviousTimestampValid = false; return INVALID_OPERATION; } // FIXME Not accurate under dynamic changes of sample rate and speed. @@ -919,10 +914,7 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times uint32_t framesWritten = i >= 0 ? playbackThread->mLatchQ.mFramesReleased[i] : mAudioTrackServerProxy->framesReleased(); - if (framesWritten < unpresentedFrames) { - mPreviousTimestampValid = false; - // return invalid result - } else { + if (framesWritten >= unpresentedFrames) { timestamp.mPosition = framesWritten - unpresentedFrames; timestamp.mTime = playbackThread->mLatchQ.mTimestamp.mTime; result = NO_ERROR; @@ -931,41 +923,6 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times result = playbackThread->getTimestamp_l(timestamp); } - // Prevent retrograde motion in timestamp. - if (result == NO_ERROR) { - if (mPreviousTimestampValid) { - if (timestamp.mTime.tv_sec < mPreviousTimestamp.mTime.tv_sec || - (timestamp.mTime.tv_sec == mPreviousTimestamp.mTime.tv_sec && - timestamp.mTime.tv_nsec < mPreviousTimestamp.mTime.tv_nsec)) { - ALOGW("WARNING - retrograde timestamp time"); - // FIXME Consider blocking this from propagating upwards. - } - - // Looking at signed delta will work even when the timestamps - // are wrapping around. - int32_t deltaPosition = static_cast<int32_t>(timestamp.mPosition - - mPreviousTimestamp.mPosition); - // position can bobble slightly as an artifact; this hides the bobble - static const int32_t MINIMUM_POSITION_DELTA = 8; - if (deltaPosition < 0) { -#define TIME_TO_NANOS(time) ((uint64_t)time.tv_sec * 1000000000 + time.tv_nsec) - ALOGW("WARNING - retrograde timestamp position corrected," - " %d = %u - %u, (at %llu, %llu nanos)", - deltaPosition, - timestamp.mPosition, - mPreviousTimestamp.mPosition, - TIME_TO_NANOS(timestamp.mTime), - TIME_TO_NANOS(mPreviousTimestamp.mTime)); -#undef TIME_TO_NANOS - } - if (deltaPosition < MINIMUM_POSITION_DELTA) { - // Current timestamp is bad. Use last valid timestamp. - timestamp = mPreviousTimestamp; - } - } - mPreviousTimestamp = timestamp; - mPreviousTimestampValid = true; - } return result; } diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 9230750..8523fc5 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -106,6 +106,7 @@ public: audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -129,6 +130,7 @@ public: virtual status_t getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -209,7 +211,7 @@ public: struct audio_patch *patches, unsigned int *generation) = 0; virtual status_t setAudioPortConfig(const struct audio_port_config *config) = 0; - virtual void clearAudioPatches(uid_t uid) = 0; + virtual void releaseResourcesForUid(uid_t uid) = 0; virtual status_t acquireSoundTriggerSession(audio_session_t *session, audio_io_handle_t *ioHandle, diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp index 144d8ad..a278375 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp @@ -315,13 +315,15 @@ void SwAudioOutputDescriptor::changeRefCount(audio_stream_type_t stream, mGlobalRefCount += delta; } if ((oldGlobalRefCount == 0) && (mGlobalRefCount > 0)) { - if ((mPolicyMix != NULL) && ((mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) { + if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) + { mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId, MIX_STATE_MIXING); } } else if ((oldGlobalRefCount > 0) && (mGlobalRefCount == 0)) { - if ((mPolicyMix != NULL) && ((mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) { + if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) + { mClientInterface->onDynamicPolicyMixStateUpdate(mPolicyMix->mRegistrationId, MIX_STATE_IDLE); } diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp index 77fc0b9..6f1998c 100644 --- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp +++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp @@ -176,14 +176,14 @@ status_t AudioPolicyMixCollection::getInputMixForAttr(audio_attributes_t attr, A ssize_t index = indexOfKey(address); if (index < 0) { - ALOGW("getInputForAttr() no policy for address %s", address.string()); + ALOGW("getInputMixForAttr() no policy for address %s", address.string()); return BAD_VALUE; } sp<AudioPolicyMix> audioPolicyMix = valueAt(index); AudioMix *mix = audioPolicyMix->getMix(); if (mix->mMixType != MIX_TYPE_PLAYERS) { - ALOGW("getInputForAttr() bad policy mix type for address %s", address.string()); + ALOGW("getInputMixForAttr() bad policy mix type for address %s", address.string()); return BAD_VALUE; } *policyMix = mix; diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 7de72de..b7eed62 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -620,6 +620,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -659,8 +660,22 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, return BAD_VALUE; } - ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x", - attributes.usage, attributes.content_type, attributes.tags, attributes.flags); + ALOGV("getOutputForAttr() usage=%d, content=%d, tag=%s flags=%08x" + " session %d selectedDeviceId %d", + attributes.usage, attributes.content_type, attributes.tags, attributes.flags, + session, selectedDeviceId); + + *stream = streamTypefromAttributesInt(&attributes); + + // Explicit routing? + sp<DeviceDescriptor> deviceDesc; + for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) { + if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) { + deviceDesc = mAvailableOutputDevices[i]; + break; + } + } + mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid); routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes); audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); @@ -672,24 +687,14 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr, ALOGV("getOutputForAttr() device 0x%x, samplingRate %d, format %x, channelMask %x, flags %x", device, samplingRate, format, channelMask, flags); - *stream = streamTypefromAttributesInt(&attributes); *output = getOutputForDevice(device, session, *stream, samplingRate, format, channelMask, flags, offloadInfo); if (*output == AUDIO_IO_HANDLE_NONE) { + mOutputRoutes.removeRoute(session); return INVALID_OPERATION; } - // Explicit routing? - sp<DeviceDescriptor> deviceDesc; - - for (size_t i = 0; i < mAvailableOutputDevices.size(); i++) { - if (mAvailableOutputDevices[i]->getId() == selectedDeviceId) { - deviceDesc = mAvailableOutputDevices[i]; - break; - } - } - mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc); return NO_ERROR; } @@ -966,24 +971,26 @@ status_t AudioPolicyManager::startOutput(audio_io_handle_t output, sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index); + // Routing? + mOutputRoutes.incRouteActivity(session); + audio_devices_t newDevice; if (outputDesc->mPolicyMix != NULL) { newDevice = AUDIO_DEVICE_OUT_REMOTE_SUBMIX; } else if (mOutputRoutes.hasRouteChanged(session)) { newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/); + checkStrategyRoute(getStrategy(stream), output); } else { newDevice = AUDIO_DEVICE_NONE; } uint32_t delayMs = 0; - // Routing? - mOutputRoutes.incRouteActivity(session); - status_t status = startSource(outputDesc, stream, newDevice, &delayMs); if (status != NO_ERROR) { mOutputRoutes.decRouteActivity(session); + return status; } // Automatically enable the remote submix input when output is started on a re routing mix // of type MIX_TYPE_RECORDERS @@ -1112,15 +1119,22 @@ status_t AudioPolicyManager::stopOutput(audio_io_handle_t output, } // Routing? + bool forceDeviceUpdate = false; if (outputDesc->mRefCount[stream] > 0) { - mOutputRoutes.decRouteActivity(session); + int activityCount = mOutputRoutes.decRouteActivity(session); + forceDeviceUpdate = (mOutputRoutes.hasRoute(session) && (activityCount == 0)); + + if (forceDeviceUpdate) { + checkStrategyRoute(getStrategy(stream), AUDIO_IO_HANDLE_NONE); + } } - return stopSource(outputDesc, stream); + return stopSource(outputDesc, stream, forceDeviceUpdate); } status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc, - audio_stream_type_t stream) + audio_stream_type_t stream, + bool forceDeviceUpdate) { // always handle stream stop, check which stream type is stopping handleEventForBeacon(stream == AUDIO_STREAM_TTS ? STOPPING_BEACON : STOPPING_OUTPUT); @@ -1135,7 +1149,7 @@ status_t AudioPolicyManager::stopSource(sp<AudioOutputDescriptor> outputDesc, outputDesc->changeRefCount(stream, -1); // store time at which the stream was stopped - see isStreamActive() - if (outputDesc->mRefCount[stream] == 0) { + if (outputDesc->mRefCount[stream] == 0 || forceDeviceUpdate) { outputDesc->mStopTime[stream] = systemTime(); audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/); // delay the device switch by twice the latency because stopOutput() is executed when @@ -1222,6 +1236,7 @@ void AudioPolicyManager::releaseOutput(audio_io_handle_t output, status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -1256,7 +1271,7 @@ status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr, break; } } - mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc); + mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid); if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX && strncmp(attr->tags, "addr=", strlen("addr=")) == 0) { @@ -1431,17 +1446,17 @@ status_t AudioPolicyManager::startInput(audio_io_handle_t input, } } + // Routing? + mInputRoutes.incRouteActivity(session); + if (inputDesc->mRefCount == 0 || mInputRoutes.hasRouteChanged(session)) { // if input maps to a dynamic policy with an activity listener, notify of state change if ((inputDesc->mPolicyMix != NULL) - && ((inputDesc->mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) { + && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) { mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId, MIX_STATE_MIXING); } - // Routing? - mInputRoutes.incRouteActivity(session); - if (mInputs.activeInputsCount() == 0) { SoundTrigger::setCaptureState(true); } @@ -1501,7 +1516,7 @@ status_t AudioPolicyManager::stopInput(audio_io_handle_t input, if (inputDesc->mRefCount == 0) { // if input maps to a dynamic policy with an activity listener, notify of state change if ((inputDesc->mPolicyMix != NULL) - && ((inputDesc->mPolicyMix->mFlags & MIX_FLAG_NOTIFY_ACTIVITY) != 0)) { + && ((inputDesc->mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0)) { mpClientInterface->onDynamicPolicyMixStateUpdate(inputDesc->mPolicyMix->mRegistrationId, MIX_STATE_IDLE); } @@ -2479,6 +2494,12 @@ status_t AudioPolicyManager::setAudioPortConfig(const struct audio_port_config * return status; } +void AudioPolicyManager::releaseResourcesForUid(uid_t uid) +{ + clearAudioPatches(uid); + clearSessionRoutes(uid); +} + void AudioPolicyManager::clearAudioPatches(uid_t uid) { for (ssize_t i = (ssize_t)mAudioPatches.size() - 1; i >= 0; i--) { @@ -2489,6 +2510,82 @@ void AudioPolicyManager::clearAudioPatches(uid_t uid) } } + +void AudioPolicyManager::checkStrategyRoute(routing_strategy strategy, + audio_io_handle_t ouptutToSkip) +{ + audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/); + SortedVector<audio_io_handle_t> outputs = getOutputsForDevice(device, mOutputs); + for (size_t j = 0; j < mOutputs.size(); j++) { + if (mOutputs.keyAt(j) == ouptutToSkip) { + continue; + } + sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(j); + if (!isStrategyActive(outputDesc, (routing_strategy)strategy)) { + continue; + } + // If the default device for this strategy is on another output mix, + // invalidate all tracks in this strategy to force re connection. + // Otherwise select new device on the output mix. + if (outputs.indexOf(mOutputs.keyAt(j)) < 0) { + for (int stream = 0; stream < AUDIO_STREAM_CNT; stream++) { + if (stream == AUDIO_STREAM_PATCH) { + continue; + } + if (getStrategy((audio_stream_type_t)stream) == strategy) { + mpClientInterface->invalidateStream((audio_stream_type_t)stream); + } + } + } else { + audio_devices_t newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/); + setOutputDevice(outputDesc, newDevice, false); + } + } +} + +void AudioPolicyManager::clearSessionRoutes(uid_t uid) +{ + // remove output routes associated with this uid + SortedVector<routing_strategy> affectedStrategies; + for (ssize_t i = (ssize_t)mOutputRoutes.size() - 1; i >= 0; i--) { + sp<SessionRoute> route = mOutputRoutes.valueAt(i); + if (route->mUid == uid) { + mOutputRoutes.removeItemsAt(i); + if (route->mDeviceDescriptor != 0) { + affectedStrategies.add(getStrategy(route->mStreamType)); + } + } + } + // reroute outputs if necessary + for (size_t i = 0; i < affectedStrategies.size(); i++) { + checkStrategyRoute(affectedStrategies[i], AUDIO_IO_HANDLE_NONE); + } + + // remove input routes associated with this uid + SortedVector<audio_source_t> affectedSources; + for (ssize_t i = (ssize_t)mInputRoutes.size() - 1; i >= 0; i--) { + sp<SessionRoute> route = mInputRoutes.valueAt(i); + if (route->mUid == uid) { + mInputRoutes.removeItemsAt(i); + if (route->mDeviceDescriptor != 0) { + affectedSources.add(route->mSource); + } + } + } + // reroute inputs if necessary + SortedVector<audio_io_handle_t> inputsToClose; + for (size_t i = 0; i < mInputs.size(); i++) { + sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i); + if (affectedSources.indexOf(inputDesc->mInputSource) >= 0) { + inputsToClose.add(inputDesc->mIoHandle); + } + } + for (size_t i = 0; i < inputsToClose.size(); i++) { + closeInput(inputsToClose[i]); + } +} + + status_t AudioPolicyManager::acquireSoundTriggerSession(audio_session_t *session, audio_io_handle_t *ioHandle, audio_devices_t *device) @@ -3563,7 +3660,8 @@ SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice( ALOGVV("getOutputsForDevice() device %04x", device); for (size_t i = 0; i < openOutputs.size(); i++) { ALOGVV("output %d isDuplicated=%d device=%04x", - i, openOutputs.valueAt(i)->isDuplicated(), openOutputs.valueAt(i)->supportedDevices()); + i, openOutputs.valueAt(i)->isDuplicated(), + openOutputs.valueAt(i)->supportedDevices()); if ((device & openOutputs.valueAt(i)->supportedDevices()) == device) { ALOGVV("getOutputsForDevice() found output %d", openOutputs.keyAt(i)); outputs.add(openOutputs.keyAt(i)); @@ -3925,7 +4023,7 @@ audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strate for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) { sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex); routing_strategy strat = getStrategy(route->mStreamType); - if (strat == strategy && route->mDeviceDescriptor != 0 /*&& route->mActivityCount != 0*/) { + if (strat == strategy && route->isActive()) { return route->mDeviceDescriptor->type(); } } @@ -4315,8 +4413,7 @@ audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t input { for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) { sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex); - if (inputSource == route->mSource && route->mDeviceDescriptor != 0 - /*&& route->mActivityCount != 0*/) { + if (inputSource == route->mSource && route->isActive()) { return route->mDeviceDescriptor->type(); } } @@ -4605,7 +4702,8 @@ void AudioPolicyManager::SessionRouteMap::log(const char* caption) { void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session, audio_stream_type_t streamType, audio_source_t source, - sp<DeviceDescriptor> descriptor) + sp<DeviceDescriptor> descriptor, + uid_t uid) { if (mMapType == MAPTYPE_INPUT && streamType != SessionRoute::STREAM_TYPE_NA) { ALOGE("Adding Output Route to InputRouteMap"); @@ -4618,14 +4716,15 @@ void AudioPolicyManager::SessionRouteMap::addRoute(audio_session_t session, sp<SessionRoute> route = indexOfKey(session) >= 0 ? valueFor(session) : 0; if (route != 0) { - if ((route->mDeviceDescriptor == 0 && descriptor != 0) || - (!route->mDeviceDescriptor->equals(descriptor))) { + if (((route->mDeviceDescriptor == 0) && (descriptor != 0)) || + ((route->mDeviceDescriptor != 0) && + ((descriptor == 0) || (!route->mDeviceDescriptor->equals(descriptor))))) { route->mChanged = true; } route->mRefCount++; route->mDeviceDescriptor = descriptor; } else { - route = new AudioPolicyManager::SessionRoute(session, streamType, source, descriptor); + route = new AudioPolicyManager::SessionRoute(session, streamType, source, descriptor, uid); route->mRefCount++; add(session, route); if (descriptor != 0) { diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index b965411..ea16864 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -109,6 +109,7 @@ public: audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -127,6 +128,7 @@ public: virtual status_t getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -207,7 +209,6 @@ public: struct audio_patch *patches, unsigned int *generation); virtual status_t setAudioPortConfig(const struct audio_port_config *config); - virtual void clearAudioPatches(uid_t uid); virtual status_t acquireSoundTriggerSession(audio_session_t *session, audio_io_handle_t *ioHandle, @@ -226,6 +227,8 @@ public: audio_io_handle_t *handle); virtual status_t stopAudioSource(audio_io_handle_t handle); + virtual void releaseResourcesForUid(uid_t uid); + // Audio policy configuration file parsing (audio_policy.conf) // TODO candidates to be moved to ConfigParsingUtils void defaultAudioPolicyConfig(void); @@ -248,31 +251,36 @@ protected: SessionRoute(audio_session_t session, audio_stream_type_t streamType, audio_source_t source, - sp<DeviceDescriptor> deviceDescriptor) - : mSession(session), + sp<DeviceDescriptor> deviceDescriptor, + uid_t uid) + : mUid(uid), + mSession(session), mDeviceDescriptor(deviceDescriptor), mRefCount(0), mActivityCount(0), mChanged(false), mStreamType(streamType), - mSource(source) {} + mSource(source) + {} - audio_session_t mSession; + void log(const char* prefix); - sp<DeviceDescriptor> mDeviceDescriptor; + bool isActive() { + return (mDeviceDescriptor != 0) && (mChanged || (mActivityCount > 0)); + } - void log(const char* prefix); + uid_t mUid; + audio_session_t mSession; + sp<DeviceDescriptor> mDeviceDescriptor; // "reference" counting - int mRefCount; // +/- on references - int mActivityCount; // +/- on start/stop - bool mChanged; - + int mRefCount; // +/- on references + int mActivityCount; // +/- on start/stop + bool mChanged; // for outputs - const audio_stream_type_t mStreamType; - + const audio_stream_type_t mStreamType; // for inputs - const audio_source_t mSource; + const audio_source_t mSource; }; class SessionRouteMap: public KeyedVector<audio_session_t, sp<SessionRoute>> { @@ -292,6 +300,7 @@ protected: } bool hasRoute(audio_session_t session); + void removeRoute(audio_session_t session); int incRouteActivity(audio_session_t session); @@ -306,7 +315,8 @@ protected: void addRoute(audio_session_t session, audio_stream_type_t streamType, audio_source_t source, - sp<DeviceDescriptor> deviceDescriptor); + sp<DeviceDescriptor> deviceDescriptor, + uid_t uid); private: // Used to mark a SessionRoute as for either inputs (mMapType == kSessionRouteMap_Input) @@ -559,7 +569,12 @@ protected: audio_devices_t device, uint32_t *delayMs); status_t stopSource(sp<AudioOutputDescriptor> outputDesc, - audio_stream_type_t stream); + audio_stream_type_t stream, + bool forceDeviceUpdate); + + void clearAudioPatches(uid_t uid); + void clearSessionRoutes(uid_t uid); + void checkStrategyRoute(routing_strategy strategy, audio_io_handle_t ouptutToSkip); uid_t mUidCached; AudioPolicyClientInterface *mpClientInterface; // audio policy client interface diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp index e6ace20..282ddeb 100644 --- a/services/audiopolicy/service/AudioPolicyEffects.cpp +++ b/services/audiopolicy/service/AudioPolicyEffects.cpp @@ -109,8 +109,8 @@ status_t AudioPolicyEffects::addInputEffects(audio_io_handle_t input, Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects; for (size_t i = 0; i < effects.size(); i++) { EffectDesc *effect = effects[i]; - sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, - audioSession, input); + sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, -1, 0, + 0, audioSession, input); status_t status = fx->initCheck(); if (status != NO_ERROR && status != ALREADY_EXISTS) { ALOGW("addInputEffects(): failed to create Fx %s on source %d", @@ -254,7 +254,7 @@ status_t AudioPolicyEffects::addOutputSessionEffects(audio_io_handle_t output, Vector <EffectDesc *> effects = mOutputStreams.valueAt(index)->mEffects; for (size_t i = 0; i < effects.size(); i++) { EffectDesc *effect = effects[i]; - sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, 0, 0, 0, + sp<AudioEffect> fx = new AudioEffect(NULL, String16("android"), &effect->mUuid, 0, 0, 0, audioSession, output); status_t status = fx->initCheck(); if (status != NO_ERROR && status != ALREADY_EXISTS) { diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index 5ceb1cf..65639c3 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -146,6 +146,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -158,7 +159,16 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, } ALOGV("getOutput()"); Mutex::Autolock _l(mLock); - return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, samplingRate, + + // if the caller is us, trust the specified uid + if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) { + uid_t newclientUid = IPCThreadState::self()->getCallingUid(); + if (uid != (uid_t)-1 && uid != newclientUid) { + ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid); + } + uid = newclientUid; + } + return mAudioPolicyManager->getOutputForAttr(attr, output, session, stream, uid, samplingRate, format, channelMask, flags, selectedDeviceId, offloadInfo); } @@ -248,6 +258,7 @@ void AudioPolicyService::doReleaseOutput(audio_io_handle_t output, status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -269,12 +280,22 @@ status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, sp<AudioPolicyEffects>audioPolicyEffects; status_t status; AudioPolicyInterface::input_type_t inputType; + // if the caller is us, trust the specified uid + if (IPCThreadState::self()->getCallingPid() != getpid_cached || uid == (uid_t)-1) { + uid_t newclientUid = IPCThreadState::self()->getCallingUid(); + if (uid != (uid_t)-1 && uid != newclientUid) { + ALOGW("%s uid %d tried to pass itself off as %d", __FUNCTION__, newclientUid, uid); + } + uid = newclientUid; + } + { Mutex::Autolock _l(mLock); // the audio_in_acoustics_t parameter is ignored by get_input() - status = mAudioPolicyManager->getInputForAttr(attr, input, session, + status = mAudioPolicyManager->getInputForAttr(attr, input, session, uid, samplingRate, format, channelMask, - flags, selectedDeviceId, &inputType); + flags, selectedDeviceId, + &inputType); audioPolicyEffects = mAudioPolicyEffects; if (status == NO_ERROR) { diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp index 433e712..13af3ef 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImplLegacy.cpp @@ -234,6 +234,7 @@ void AudioPolicyService::doReleaseOutput(audio_io_handle_t output, status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid __unused, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, @@ -565,6 +566,7 @@ status_t AudioPolicyService::getOutputForAttr(const audio_attributes_t *attr, audio_io_handle_t *output, audio_session_t session __unused, audio_stream_type_t *stream, + uid_t uid __unused, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp index ccf9f9b..c5f4fb7 100644 --- a/services/audiopolicy/service/AudioPolicyService.cpp +++ b/services/audiopolicy/service/AudioPolicyService.cpp @@ -177,7 +177,7 @@ void AudioPolicyService::removeNotificationClient(uid_t uid) { Mutex::Autolock _l(mLock); if (mAudioPolicyManager) { - mAudioPolicyManager->clearAudioPatches(uid); + mAudioPolicyManager->releaseResourcesForUid(uid); } } #endif diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index 07ea96b..eb50cdd 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -80,6 +80,7 @@ public: audio_io_handle_t *output, audio_session_t session, audio_stream_type_t *stream, + uid_t uid, uint32_t samplingRate = 0, audio_format_t format = AUDIO_FORMAT_DEFAULT, audio_channel_mask_t channelMask = 0, @@ -98,6 +99,7 @@ public: virtual status_t getInputForAttr(const audio_attributes_t *attr, audio_io_handle_t *input, audio_session_t session, + uid_t uid, uint32_t samplingRate, audio_format_t format, audio_channel_mask_t channelMask, diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 8c5c43a..e28464d 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -890,9 +890,12 @@ status_t CameraService::handleEvictionsLocked(const String8& cameraId, int clien if (current != nullptr) { auto clientSp = current->getValue(); if (clientSp.get() != nullptr) { // should never be needed - if (clientSp->getRemote() == remoteCallback) { + if (!clientSp->canCastToApiClient(effectiveApiLevel)) { + ALOGW("CameraService connect called from same client, but with a different" + " API level, evicting prior client..."); + } else if (clientSp->getRemote() == remoteCallback) { ALOGI("CameraService::connect X (PID %d) (second call from same" - "app binder, returning the same client)", clientPid); + " app binder, returning the same client)", clientPid); *client = clientSp; return NO_ERROR; } @@ -1754,6 +1757,11 @@ int CameraService::BasicClient::getClientPid() const { return mClientPid; } +bool CameraService::BasicClient::canCastToApiClient(apiLevel level) const { + // Defaults to API2. + return level == API_2; +} + status_t CameraService::BasicClient::startCameraOps() { int32_t res; // Notify app ops that the camera is not available @@ -1866,6 +1874,10 @@ void CameraService::Client::disconnect() { BasicClient::disconnect(); } +bool CameraService::Client::canCastToApiClient(apiLevel level) const { + return level == API_1; +} + CameraService::Client::OpsCallback::OpsCallback(wp<BasicClient> client): mClient(client) { } diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index 84e61c5..a8b4c4a 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -65,6 +65,7 @@ public: class Client; class BasicClient; + // The effective API level. The Camera2 API running in LEGACY mode counts as API_1. enum apiLevel { API_1 = 1, API_2 = 2 @@ -215,6 +216,10 @@ public: // Get the PID of the application client using this virtual int getClientPid() const; + + // Check what API level is used for this client. This is used to determine which + // superclass this can be cast to. + virtual bool canCastToApiClient(apiLevel level) const; protected: BasicClient(const sp<CameraService>& cameraService, const sp<IBinder>& remoteCallback, @@ -323,6 +328,10 @@ public: virtual void notifyError(ICameraDeviceCallbacks::CameraErrorCode errorCode, const CaptureResultExtras& resultExtras); + + // Check what API level is used for this client. This is used to determine which + // superclass this can be cast to. + virtual bool canCastToApiClient(apiLevel level) const; protected: // Convert client from cookie. static sp<CameraService::Client> getClientFromCookie(void* user); diff --git a/services/camera/libcameraservice/api1/client2/Parameters.cpp b/services/camera/libcameraservice/api1/client2/Parameters.cpp index 6b0f8b5..c3a6842 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.cpp +++ b/services/camera/libcameraservice/api1/client2/Parameters.cpp @@ -2100,12 +2100,7 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { delete[] reqMeteringAreas; - /* don't include jpeg thumbnail size - it's valid for - it to be set to (0,0), meaning 'no thumbnail' */ - CropRegion crop = calculateCropRegion( (CropRegion::Outputs)( - CropRegion::OUTPUT_PREVIEW | - CropRegion::OUTPUT_VIDEO | - CropRegion::OUTPUT_PICTURE )); + CropRegion crop = calculateCropRegion(/*previewOnly*/ false); int32_t reqCropRegion[4] = { static_cast<int32_t>(crop.left), static_cast<int32_t>(crop.top), @@ -2603,7 +2598,7 @@ int Parameters::cropXToArray(int x) const { ALOG_ASSERT(x >= 0, "Crop-relative X coordinate = '%d' is out of bounds" "(lower = 0)", x); - CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW); + CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true); ALOG_ASSERT(x < previewCrop.width, "Crop-relative X coordinate = '%d' " "is out of bounds (upper = %f)", x, previewCrop.width); @@ -2619,7 +2614,7 @@ int Parameters::cropYToArray(int y) const { ALOG_ASSERT(y >= 0, "Crop-relative Y coordinate = '%d' is out of bounds " "(lower = 0)", y); - CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW); + CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true); ALOG_ASSERT(y < previewCrop.height, "Crop-relative Y coordinate = '%d' is " "out of bounds (upper = %f)", y, previewCrop.height); @@ -2634,12 +2629,12 @@ int Parameters::cropYToArray(int y) const { } int Parameters::normalizedXToCrop(int x) const { - CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW); + CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true); return (x + 1000) * (previewCrop.width - 1) / 2000; } int Parameters::normalizedYToCrop(int y) const { - CropRegion previewCrop = calculateCropRegion(CropRegion::OUTPUT_PREVIEW); + CropRegion previewCrop = calculateCropRegion(/*previewOnly*/ true); return (y + 1000) * (previewCrop.height - 1) / 2000; } @@ -2855,8 +2850,7 @@ Vector<Parameters::Size> Parameters::getAvailableJpegSizes() { return jpegSizes; } -Parameters::CropRegion Parameters::calculateCropRegion( - Parameters::CropRegion::Outputs outputs) const { +Parameters::CropRegion Parameters::calculateCropRegion(bool previewOnly) const { float zoomLeft, zoomTop, zoomWidth, zoomHeight; @@ -2880,90 +2874,45 @@ Parameters::CropRegion Parameters::calculateCropRegion( maxDigitalZoom.data.f[0], zoomIncrement, zoomRatio, previewWidth, previewHeight, fastInfo.arrayWidth, fastInfo.arrayHeight); - /* - * Assumption: On the HAL side each stream buffer calculates its crop - * rectangle as follows: - * cropRect = (zoomLeft, zoomRight, - * zoomWidth, zoomHeight * zoomWidth / outputWidth); - * - * Note that if zoomWidth > bufferWidth, the new cropHeight > zoomHeight - * (we can then get into trouble if the cropHeight > arrayHeight). - * By selecting the zoomRatio based on the smallest outputRatio, we - * guarantee this will never happen. - */ + if (previewOnly) { + // Calculate a tight crop region for the preview stream only + float previewRatio = static_cast<float>(previewWidth) / previewHeight; - // Enumerate all possible output sizes, select the one with the smallest - // aspect ratio - float minOutputWidth, minOutputHeight, minOutputRatio; - { - float outputSizes[][2] = { - { static_cast<float>(previewWidth), - static_cast<float>(previewHeight) }, - { static_cast<float>(videoWidth), - static_cast<float>(videoHeight) }, - { static_cast<float>(jpegThumbSize[0]), - static_cast<float>(jpegThumbSize[1]) }, - { static_cast<float>(pictureWidth), - static_cast<float>(pictureHeight) }, - }; - - minOutputWidth = outputSizes[0][0]; - minOutputHeight = outputSizes[0][1]; - minOutputRatio = minOutputWidth / minOutputHeight; - for (unsigned int i = 0; - i < sizeof(outputSizes) / sizeof(outputSizes[0]); - ++i) { - - // skip over outputs we don't want to consider for the crop region - if ( !((1 << i) & outputs) ) { - continue; - } - - float outputWidth = outputSizes[i][0]; - float outputHeight = outputSizes[i][1]; - float outputRatio = outputWidth / outputHeight; - - if (minOutputRatio > outputRatio) { - minOutputRatio = outputRatio; - minOutputWidth = outputWidth; - minOutputHeight = outputHeight; - } + /* Ensure that the width/height never go out of bounds + * by scaling across a diffent dimension if an out-of-bounds + * possibility exists. + * + * e.g. if the previewratio < arrayratio and e.g. zoomratio = 1.0, then by + * calculating the zoomWidth from zoomHeight we'll actually get a + * zoomheight > arrayheight + */ + float arrayRatio = 1.f * fastInfo.arrayWidth / fastInfo.arrayHeight; + if (previewRatio >= arrayRatio) { + // Adjust the height based on the width + zoomWidth = fastInfo.arrayWidth / zoomRatio; + zoomHeight = zoomWidth * + previewHeight / previewWidth; - // and then use this output ratio instead of preview output ratio - ALOGV("Enumerating output ratio %f = %f / %f, min is %f", - outputRatio, outputWidth, outputHeight, minOutputRatio); + } else { + // Adjust the width based on the height + zoomHeight = fastInfo.arrayHeight / zoomRatio; + zoomWidth = zoomHeight * + previewWidth / previewHeight; } - } - - /* Ensure that the width/height never go out of bounds - * by scaling across a diffent dimension if an out-of-bounds - * possibility exists. - * - * e.g. if the previewratio < arrayratio and e.g. zoomratio = 1.0, then by - * calculating the zoomWidth from zoomHeight we'll actually get a - * zoomheight > arrayheight - */ - float arrayRatio = 1.f * fastInfo.arrayWidth / fastInfo.arrayHeight; - if (minOutputRatio >= arrayRatio) { - // Adjust the height based on the width - zoomWidth = fastInfo.arrayWidth / zoomRatio; - zoomHeight = zoomWidth * - minOutputHeight / minOutputWidth; - } else { - // Adjust the width based on the height + // Calculate the global crop region with a shape matching the active + // array. + zoomWidth = fastInfo.arrayWidth / zoomRatio; zoomHeight = fastInfo.arrayHeight / zoomRatio; - zoomWidth = zoomHeight * - minOutputWidth / minOutputHeight; } - // centering the zoom area within the active area + + // center the zoom area within the active area zoomLeft = (fastInfo.arrayWidth - zoomWidth) / 2; zoomTop = (fastInfo.arrayHeight - zoomHeight) / 2; ALOGV("Crop region calculated (x=%d,y=%d,w=%f,h=%f) for zoom=%d", (int32_t)zoomLeft, (int32_t)zoomTop, zoomWidth, zoomHeight, this->zoom); - CropRegion crop = { zoomLeft, zoomTop, zoomWidth, zoomHeight }; return crop; } diff --git a/services/camera/libcameraservice/api1/client2/Parameters.h b/services/camera/libcameraservice/api1/client2/Parameters.h index e628a7e..46d48bc 100644 --- a/services/camera/libcameraservice/api1/client2/Parameters.h +++ b/services/camera/libcameraservice/api1/client2/Parameters.h @@ -271,21 +271,16 @@ struct Parameters { // if video snapshot size is currently overridden bool isJpegSizeOverridden(); - // Calculate the crop region rectangle based on current stream sizes + // Calculate the crop region rectangle, either tightly about the preview + // resolution, or a region just based on the active array; both take + // into account the current zoom level. struct CropRegion { float left; float top; float width; float height; - - enum Outputs { - OUTPUT_PREVIEW = 0x01, - OUTPUT_VIDEO = 0x02, - OUTPUT_JPEG_THUMBNAIL = 0x04, - OUTPUT_PICTURE = 0x08, - }; }; - CropRegion calculateCropRegion(CropRegion::Outputs outputs) const; + CropRegion calculateCropRegion(bool previewOnly) const; // Calculate the field of view of the high-resolution JPEG capture status_t calculatePictureFovs(float *horizFov, float *vertFov) const; |