Merge "Add MTP and PTP OS descriptors."
diff --git a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
index 6a4f8d5..caff393 100644
--- a/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
+++ b/drm/mediadrm/plugins/clearkey/InitDataParser.cpp
@@ -136,7 +136,7 @@
AString encodedId;
for (size_t i = 0; i < keyIds.size(); ++i) {
encodedId.clear();
- android::encodeBase64(keyIds[i], kKeyIdSize, &encodedId);
+ android::encodeBase64Url(keyIds[i], kKeyIdSize, &encodedId);
if (i != 0) {
request.append(",");
}
diff --git a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
index 84ed242..8c49656 100644
--- a/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/InitDataParserUnittest.cpp
@@ -59,7 +59,7 @@
(size_t)requestString.find(kRequestSuffix));
for (size_t i = 0; i < expectedKeys.size(); ++i) {
AString encodedIdAString;
- android::encodeBase64(expectedKeys[i], kKeyIdSize,
+ android::encodeBase64Url(expectedKeys[i], kKeyIdSize,
&encodedIdAString);
String8 encodedId(encodedIdAString.c_str());
encodedId.removeAll(kBase64Padding);
@@ -231,5 +231,4 @@
attemptParseExpectingFailure(initData, kCencMimeType);
}
-
} // namespace clearkeydrm
diff --git a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
index c3b0d84..d9f3ea6 100644
--- a/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
+++ b/drm/mediadrm/plugins/clearkey/tests/JsonWebKeyUnittest.cpp
@@ -284,14 +284,14 @@
"\"keys\":"
"[{"
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAx\""
- "\"k\":\"SGVsbG8gRnJpZW5kISE\""
+ "\"k\":\"SGVsbG8gRnJpZW5kICE-Pw\""
"\"kty\":\"oct\""
"\"alg\":\"A128KW1\""
"}"
"{"
"\"kty\":\"oct\""
"\"alg\":\"A128KW2\""
- "\"k\":\"SGVsbG8gRnJpZW5kIQ\""
+ "\"k\":\"SGVsbG8gRnJpZW5kICE_\""
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAy\""
"}"
"{"
@@ -303,7 +303,7 @@
"{"
"\"alg\":\"A128KW3\""
"\"kid\":\"Y2xlYXJrZXlrZXlpZDAz\""
- "\"k\":\"R29vZCBkYXkh\""
+ "\"k\":\"SGVsbG8gPz4-IEZyaWVuZCA_Pg\""
"\"kty\":\"oct\""
"}]"
"}");
@@ -313,8 +313,8 @@
EXPECT_TRUE(keys.size() == 3);
const String8 clearKeys[] =
- { String8("Hello Friend!!"), String8("Hello Friend!"),
- String8("Good day!") };
+ { String8("Hello Friend !>?"), String8("Hello Friend !?"),
+ String8("Hello ?>> Friend ?>") };
verifyKeys(keys, clearKeys);
}
diff --git a/include/media/IAudioRecord.h b/include/media/IAudioRecord.h
deleted file mode 120000
index 7fbf8f2..0000000
--- a/include/media/IAudioRecord.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libaudioclient/include/media/IAudioRecord.h
\ No newline at end of file
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index 302641f..a3aaece 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -37,6 +37,8 @@
namespace android {
+namespace media {
+
// The native VolumeShaper class mirrors the java VolumeShaper class;
// in addition, the native class contains implementation for actual operation.
//
@@ -101,7 +103,7 @@
* See "frameworks/base/media/java/android/media/VolumeShaper.java" for
* details on the Java implementation.
*/
- class Configuration : public Interpolator<S, T>, public RefBase {
+ class Configuration : public Interpolator<S, T>, public RefBase, public Parcelable {
public:
// Must match with VolumeShaper.java in frameworks/base.
enum Type : int32_t {
@@ -283,7 +285,7 @@
}
// The parcel layout must match VolumeShaper.java
- status_t writeToParcel(Parcel *parcel) const {
+ status_t writeToParcel(Parcel *parcel) const override {
if (parcel == nullptr) return BAD_VALUE;
return parcel->writeInt32((int32_t)mType)
?: parcel->writeInt32(mId)
@@ -294,17 +296,17 @@
?: Interpolator<S, T>::writeToParcel(parcel);
}
- status_t readFromParcel(const Parcel &parcel) {
+ status_t readFromParcel(const Parcel *parcel) override {
int32_t type, optionFlags;
- return parcel.readInt32(&type)
+ return parcel->readInt32(&type)
?: setType((Type)type)
- ?: parcel.readInt32(&mId)
+ ?: parcel->readInt32(&mId)
?: mType == TYPE_ID
? NO_ERROR
- : parcel.readInt32(&optionFlags)
+ : parcel->readInt32(&optionFlags)
?: setOptionFlags((OptionFlag)optionFlags)
- ?: parcel.readDouble(&mDurationMs)
- ?: Interpolator<S, T>::readFromParcel(parcel)
+ ?: parcel->readDouble(&mDurationMs)
+ ?: Interpolator<S, T>::readFromParcel(*parcel)
?: checkCurve();
}
@@ -336,7 +338,7 @@
* See "frameworks/base/media/java/android/media/VolumeShaper.java" for
* details on the Java implementation.
*/
- class Operation : public RefBase {
+ class Operation : public RefBase, public Parcelable {
public:
// Must match with VolumeShaper.java.
enum Flag : int32_t {
@@ -418,18 +420,18 @@
return NO_ERROR;
}
- status_t writeToParcel(Parcel *parcel) const {
+ status_t writeToParcel(Parcel *parcel) const override {
if (parcel == nullptr) return BAD_VALUE;
return parcel->writeInt32((int32_t)mFlags)
?: parcel->writeInt32(mReplaceId)
?: parcel->writeFloat(mXOffset);
}
- status_t readFromParcel(const Parcel &parcel) {
+ status_t readFromParcel(const Parcel *parcel) override {
int32_t flags;
- return parcel.readInt32(&flags)
- ?: parcel.readInt32(&mReplaceId)
- ?: parcel.readFloat(&mXOffset)
+ return parcel->readInt32(&flags)
+ ?: parcel->readInt32(&mReplaceId)
+ ?: parcel->readFloat(&mXOffset)
?: setFlags((Flag)flags);
}
@@ -455,7 +457,7 @@
* See "frameworks/base/media/java/android/media/VolumeShaper.java" for
* details on the Java implementation.
*/
- class State : public RefBase {
+ class State : public RefBase, public Parcelable {
public:
State(T volume, S xOffset)
: mVolume(volume)
@@ -481,15 +483,15 @@
mXOffset = xOffset;
}
- status_t writeToParcel(Parcel *parcel) const {
+ status_t writeToParcel(Parcel *parcel) const override {
if (parcel == nullptr) return BAD_VALUE;
return parcel->writeFloat(mVolume)
?: parcel->writeFloat(mXOffset);
}
- status_t readFromParcel(const Parcel &parcel) {
- return parcel.readFloat(&mVolume)
- ?: parcel.readFloat(&mXOffset);
+ status_t readFromParcel(const Parcel *parcel) override {
+ return parcel->readFloat(&mVolume)
+ ?: parcel->readFloat(&mXOffset);
}
std::string toString() const {
@@ -1020,6 +1022,8 @@
std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
}; // VolumeHandler
+} // namespace media
+
} // namespace android
#pragma pop_macro("LOG_TAG")
diff --git a/media/img_utils/src/TiffWriter.cpp b/media/img_utils/src/TiffWriter.cpp
index 564474f..1711242 100644
--- a/media/img_utils/src/TiffWriter.cpp
+++ b/media/img_utils/src/TiffWriter.cpp
@@ -350,7 +350,7 @@
if (nextIfd == NULL) {
break;
}
- ifd = nextIfd;
+ ifd = std::move(nextIfd);
}
return ifd;
}
diff --git a/media/libaaudio/examples/utils/AAudioExampleUtils.h b/media/libaaudio/examples/utils/AAudioExampleUtils.h
index 6cbcc58..9ef62c9 100644
--- a/media/libaaudio/examples/utils/AAudioExampleUtils.h
+++ b/media/libaaudio/examples/utils/AAudioExampleUtils.h
@@ -17,9 +17,14 @@
#ifndef AAUDIO_EXAMPLE_UTILS_H
#define AAUDIO_EXAMPLE_UTILS_H
-#include <unistd.h>
+#include <atomic>
+#include <linux/futex.h>
#include <sched.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
#include <aaudio/AAudio.h>
+#include <utils/Errors.h>
#define NANOS_PER_MICROSECOND ((int64_t)1000)
#define NANOS_PER_MILLISECOND (NANOS_PER_MICROSECOND * 1000)
@@ -40,6 +45,12 @@
return modeText;
}
+static void convertNanosecondsToTimespec(int64_t nanoseconds, struct timespec *time) {
+ time->tv_sec = nanoseconds / NANOS_PER_SECOND;
+ // Calculate the fractional nanoseconds. Avoids expensive % operation.
+ time->tv_nsec = nanoseconds - (time->tv_sec * NANOS_PER_SECOND);
+}
+
static int64_t getNanoseconds(clockid_t clockId = CLOCK_MONOTONIC) {
struct timespec time;
int result = clock_gettime(clockId, &time);
@@ -79,4 +90,77 @@
return latencyMillis;
}
+// ================================================================================
+// These Futex calls are common online examples.
+static android::status_t sys_futex(void *addr1, int op, int val1,
+ struct timespec *timeout, void *addr2, int val3) {
+ android::status_t result = (android::status_t) syscall(SYS_futex, addr1,
+ op, val1, timeout,
+ addr2, val3);
+ return (result == 0) ? 0 : -errno;
+}
+
+static android::status_t futex_wake(void *addr, int numWake) {
+ // Use _PRIVATE because we are just using the futex in one process.
+ return sys_futex(addr, FUTEX_WAKE_PRIVATE, numWake, NULL, NULL, 0);
+}
+
+static android::status_t futex_wait(void *addr, int current, struct timespec *time) {
+ // Use _PRIVATE because we are just using the futex in one process.
+ return sys_futex(addr, FUTEX_WAIT_PRIVATE, current, time, NULL, 0);
+}
+
+// TODO better name?
+/**
+ * The WakeUp class is used to send a wakeup signal to one or more sleeping threads.
+ */
+class WakeUp {
+public:
+ WakeUp() : mValue(0) {}
+ explicit WakeUp(int32_t value) : mValue(value) {}
+
+ /**
+ * Wait until the internal value no longer matches the given value.
+ * Note that this code uses a futex, which is subject to spurious wake-ups.
+ * So check to make sure that the desired condition has been met.
+ *
+ * @return zero if the value changes or various negative errors including
+ * -ETIMEDOUT if a timeout occurs,
+ * or -EINTR if interrupted by a signal,
+ * or -EAGAIN or -EWOULDBLOCK if the internal value does not match the specified value
+ */
+ android::status_t wait(int32_t value, int64_t timeoutNanoseconds) {
+ struct timespec time;
+ convertNanosecondsToTimespec(timeoutNanoseconds, &time);
+ return futex_wait(&mValue, value, &time);
+ }
+
+ /**
+ * Increment value and wake up any threads that need to be woken.
+ *
+ * @return number of waiters woken up
+ */
+ android::status_t wake() {
+ ++mValue;
+ return futex_wake(&mValue, INT_MAX);
+ }
+
+ /**
+ * Set value and wake up any threads that need to be woken.
+ *
+ * @return number of waiters woken up
+ */
+ android::status_t wake(int32_t value) {
+ mValue.store(value);
+ return futex_wake(&mValue, INT_MAX);
+ }
+
+ int32_t get() {
+ return mValue.load();
+ }
+
+private:
+ std::atomic<int32_t> mValue;
+};
+
#endif // AAUDIO_EXAMPLE_UTILS_H
diff --git a/media/libaaudio/examples/utils/AAudioSimplePlayer.h b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
index cc0cb34..d2e7f23 100644
--- a/media/libaaudio/examples/utils/AAudioSimplePlayer.h
+++ b/media/libaaudio/examples/utils/AAudioSimplePlayer.h
@@ -23,6 +23,7 @@
#include <sched.h>
#include <aaudio/AAudio.h>
+#include <atomic>
#include "AAudioArgsParser.h"
#include "SineGenerator.h"
@@ -219,18 +220,26 @@
AAudioStream *mStream = nullptr;
aaudio_sharing_mode_t mRequestedSharingMode = SHARING_MODE;
aaudio_performance_mode_t mRequestedPerformanceMode = PERFORMANCE_MODE;
+
};
typedef struct SineThreadedData_s {
+
SineGenerator sineOsc1;
SineGenerator sineOsc2;
int64_t framesTotal = 0;
int64_t nextFrameToGlitch = FORCED_UNDERRUN_PERIOD_FRAMES;
int32_t minNumFrames = INT32_MAX;
int32_t maxNumFrames = 0;
- int scheduler;
+
+ int scheduler = 0;
bool schedulerChecked = false;
bool forceUnderruns = false;
+
+ AAudioSimplePlayer simplePlayer;
+ int32_t callbackCount = 0;
+ WakeUp waker{AAUDIO_OK};
+
} SineThreadedData_t;
// Callback function that fills the audio output buffer.
@@ -247,6 +256,7 @@
return AAUDIO_CALLBACK_RESULT_STOP;
}
SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
+ sineData->callbackCount++;
sineData->framesTotal += numFrames;
@@ -304,9 +314,16 @@
void SimplePlayerErrorCallbackProc(
AAudioStream *stream __unused,
void *userData __unused,
- aaudio_result_t error)
-{
- printf("Error Callback, error: %d\n",(int)error);
+ aaudio_result_t error) {
+ // should not happen but just in case...
+ if (userData == nullptr) {
+ printf("ERROR - MyPlayerErrorCallbackProc needs userData\n");
+ return;
+ }
+ SineThreadedData_t *sineData = (SineThreadedData_t *) userData;
+ android::status_t ret = sineData->waker.wake(error);
+ printf("Error Callback, error: %d, futex wake returns %d\n", error, ret);
}
+
#endif //AAUDIO_SIMPLE_PLAYER_H
diff --git a/media/libaaudio/examples/utils/SineGenerator.h b/media/libaaudio/examples/utils/SineGenerator.h
index 64b772d..a755582 100644
--- a/media/libaaudio/examples/utils/SineGenerator.h
+++ b/media/libaaudio/examples/utils/SineGenerator.h
@@ -58,6 +58,13 @@
}
}
+ void setAmplitude(double amplitude) {
+ mAmplitude = amplitude;
+ }
+ double getAmplitude() const {
+ return mAmplitude;
+ }
+
private:
void advancePhase() {
mPhase += mPhaseIncrement;
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 071ca87..2280b72 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -15,6 +15,7 @@
*/
// Play sine waves using an AAudio callback.
+// If a disconnection occurs then reopen the stream on the new device.
#include <assert.h>
#include <unistd.h>
@@ -22,33 +23,32 @@
#include <sched.h>
#include <stdio.h>
#include <math.h>
+#include <string.h>
#include <time.h>
#include <aaudio/AAudio.h>
#include "AAudioExampleUtils.h"
#include "AAudioSimplePlayer.h"
#include "../../utils/AAudioSimplePlayer.h"
-int main(int argc, const char **argv)
+/**
+ * Open stream, play some sine waves, then close the stream.
+ *
+ * @param argParser
+ * @return AAUDIO_OK or negative error code
+ */
+static aaudio_result_t testOpenPlayClose(AAudioArgsParser &argParser)
{
- AAudioArgsParser argParser;
- AAudioSimplePlayer player;
SineThreadedData_t myData;
- aaudio_result_t result;
- int32_t actualSampleRate;
+ AAudioSimplePlayer &player = myData.simplePlayer;
+ aaudio_result_t result = AAUDIO_OK;
+ bool disconnected = false;
+ int64_t startedAtNanos;
- // Make printf print immediately so that debug info is not stuck
- // in a buffer if we hang or crash.
- setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
-
- printf("%s - Play a sine sweep using an AAudio callback V0.1.3\n", argv[0]);
-
+ printf("----------------------- run complete test --------------------------\n");
myData.schedulerChecked = false;
+ myData.callbackCount = 0;
myData.forceUnderruns = false; // set true to test AAudioStream_getXRunCount()
- if (argParser.parseArgs(argc, argv)) {
- return EXIT_FAILURE;
- }
-
result = player.open(argParser,
SimplePlayerDataCallbackProc, SimplePlayerErrorCallbackProc, &myData);
if (result != AAUDIO_OK) {
@@ -58,13 +58,19 @@
argParser.compareWithStream(player.getStream());
- actualSampleRate = player.getSampleRate();
- myData.sineOsc1.setup(440.0, actualSampleRate);
- myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
- myData.sineOsc2.setup(660.0, actualSampleRate);
- myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
+ // Setup sine wave generators.
+ {
+ int32_t actualSampleRate = player.getSampleRate();
+ myData.sineOsc1.setup(440.0, actualSampleRate);
+ myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
+ myData.sineOsc1.setAmplitude(0.2);
+ myData.sineOsc2.setup(660.0, actualSampleRate);
+ myData.sineOsc2.setSweep(350.0, 900.0, 7.0);
+ myData.sineOsc2.setAmplitude(0.2);
+ }
#if 0
+ // writes not allowed for callback streams
result = player.prime(); // FIXME crashes AudioTrack.cpp
if (result != AAUDIO_OK) {
fprintf(stderr, "ERROR - player.prime() returned %d\n", result);
@@ -78,34 +84,32 @@
goto error;
}
+ // Play a sine wave in the background.
printf("Sleep for %d seconds while audio plays in a callback thread.\n",
argParser.getDurationSeconds());
+ startedAtNanos = getNanoseconds(CLOCK_MONOTONIC);
for (int second = 0; second < argParser.getDurationSeconds(); second++)
{
- const struct timespec request = { .tv_sec = 1, .tv_nsec = 0 };
- (void) clock_nanosleep(CLOCK_MONOTONIC, 0 /*flags*/, &request, NULL /*remain*/);
-
- aaudio_stream_state_t state;
- result = AAudioStream_waitForStateChange(player.getStream(),
- AAUDIO_STREAM_STATE_CLOSED,
- &state,
- 0);
+ // Sleep a while. Wake up early if there is an error, for example a DISCONNECT.
+ long ret = myData.waker.wait(AAUDIO_OK, NANOS_PER_SECOND);
+ int64_t millis = (getNanoseconds(CLOCK_MONOTONIC) - startedAtNanos) / NANOS_PER_MILLISECOND;
+ result = myData.waker.get();
+ printf("wait() returns %ld, aaudio_result = %d, at %6d millis"
+ ", second = %d, framesWritten = %8d, underruns = %d\n",
+ ret, result, (int) millis,
+ second,
+ (int) AAudioStream_getFramesWritten(player.getStream()),
+ (int) AAudioStream_getXRunCount(player.getStream()));
if (result != AAUDIO_OK) {
- fprintf(stderr, "ERROR - AAudioStream_waitForStateChange() returned %d\n", result);
- goto error;
- }
- if (state != AAUDIO_STREAM_STATE_STARTING && state != AAUDIO_STREAM_STATE_STARTED) {
- printf("Stream state is %d %s!\n", state, AAudio_convertStreamStateToText(state));
+ if (result == AAUDIO_ERROR_DISCONNECTED) {
+ disconnected = true;
+ }
break;
}
- printf("framesWritten = %d, underruns = %d\n",
- (int) AAudioStream_getFramesWritten(player.getStream()),
- (int) AAudioStream_getXRunCount(player.getStream())
- );
}
- printf("Woke up now.\n");
+ printf("AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- printf("call stop()\n");
+ printf("call stop() callback # = %d\n", myData.callbackCount);
result = player.stop();
if (result != AAUDIO_OK) {
goto error;
@@ -126,10 +130,28 @@
printf("max numFrames = %8d\n", (int) myData.maxNumFrames);
printf("SUCCESS\n");
- return EXIT_SUCCESS;
error:
player.close();
- printf("exiting - AAudio result = %d = %s\n", result, AAudio_convertResultToText(result));
- return EXIT_FAILURE;
+ return disconnected ? AAUDIO_ERROR_DISCONNECTED : result;
}
+int main(int argc, const char **argv)
+{
+ AAudioArgsParser argParser;
+ aaudio_result_t result;
+
+ // Make printf print immediately so that debug info is not stuck
+ // in a buffer if we hang or crash.
+ setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
+
+ printf("%s - Play a sine sweep using an AAudio callback V0.1.2\n", argv[0]);
+
+ if (argParser.parseArgs(argc, argv)) {
+ return EXIT_FAILURE;
+ }
+
+ // Keep looping until we can complete the test without disconnecting.
+ while((result = testOpenPlayClose(argParser)) == AAUDIO_ERROR_DISCONNECTED);
+
+ return (result) ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
index c13fa67..112a192 100644
--- a/media/libaaudio/src/Android.mk
+++ b/media/libaaudio/src/Android.mk
@@ -60,7 +60,8 @@
binding/RingBufferParcelable.cpp \
binding/SharedMemoryParcelable.cpp \
binding/SharedRegionParcelable.cpp \
- ../../libaudioclient/aidl/android/media/IAudioRecord.aidl
+ ../../libaudioclient/aidl/android/media/IAudioRecord.aidl \
+ ../../libaudioclient/aidl/android/media/IPlayer.aidl
LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index a02311b..98e8d95 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -20,6 +20,7 @@
// The headers for these interfaces will be available to any modules that
// include libaudioclient, at the path "aidl/package/path/BnFoo.h"
"aidl/android/media/IAudioRecord.aidl",
+ "aidl/android/media/IPlayer.aidl",
"AudioEffect.cpp",
"AudioPolicy.cpp",
@@ -49,7 +50,7 @@
],
export_shared_lib_headers: ["libbinder"],
- local_include_dirs: ["include/media"],
+ local_include_dirs: ["include/media", "aidl"],
header_libs: ["libaudioclient_headers"],
export_header_lib_headers: ["libaudioclient_headers"],
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 31e1e2b..0314dec 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -39,6 +39,8 @@
namespace android {
// ---------------------------------------------------------------------------
+using media::VolumeShaper;
+
// TODO: Move to a separate .h
template <typename T>
@@ -63,6 +65,14 @@
return tv.tv_sec * 1000000ll + tv.tv_nsec / 1000;
}
+// TODO move to audio_utils.
+static inline struct timespec convertNsToTimespec(int64_t ns) {
+ struct timespec tv;
+ tv.tv_sec = static_cast<time_t>(ns / NANOS_PER_SECOND);
+ tv.tv_nsec = static_cast<long>(ns % NANOS_PER_SECOND);
+ return tv;
+}
+
// current monotonic time in microseconds.
static int64_t getNowUs()
{
@@ -539,7 +549,8 @@
mUpdatePeriod = 0;
mPosition = 0;
mReleased = 0;
- mStartUs = 0;
+ mStartNs = 0;
+ mStartFromZeroUs = 0;
AudioSystem::acquireAudioSessionId(mSessionId, mClientPid);
mSequence = 1;
mObservedSequence = mSequence;
@@ -553,7 +564,7 @@
mFramesWritten = 0;
mFramesWrittenServerOffset = 0;
mFramesWrittenAtRestore = -1; // -1 is a unique initializer.
- mVolumeHandler = new VolumeHandler();
+ mVolumeHandler = new media::VolumeHandler();
return NO_ERROR;
}
@@ -587,6 +598,7 @@
mStartEts.clear();
}
}
+ mStartNs = systemTime(); // save this for timestamp adjustment after starting.
if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
// reset current position as seen by client to 0
mPosition = 0;
@@ -615,7 +627,7 @@
// since the flush is asynchronous and stop may not fully drain.
// We save the time when the track is started to later verify whether
// the counters are realistic (i.e. start from zero after this time).
- mStartUs = getNowUs();
+ mStartFromZeroUs = mStartNs / 1000;
// force refresh of remaining frames by processAudioBuffer() as last
// write before stop could be partial.
@@ -2571,8 +2583,7 @@
if (at < limit) {
ALOGV("timestamp pause lag:%lld adjusting from %lld to %lld",
(long long)lag, (long long)at, (long long)limit);
- timestamp.mTime.tv_sec = limit / NANOS_PER_SECOND;
- timestamp.mTime.tv_nsec = limit % NANOS_PER_SECOND; // compiler opt.
+ timestamp.mTime = convertNsToTimespec(limit);
}
}
mPreviousLocation = location;
@@ -2615,18 +2626,18 @@
// the previous song under gapless playback.
// However, we sometimes see zero timestamps, then a glitch of
// the previous song's position, and then correct timestamps afterwards.
- if (mStartUs != 0 && mSampleRate != 0) {
+ if (mStartFromZeroUs != 0 && mSampleRate != 0) {
static const int kTimeJitterUs = 100000; // 100 ms
static const int k1SecUs = 1000000;
const int64_t timeNow = getNowUs();
- if (timeNow < mStartUs + k1SecUs) { // within first second of starting
+ if (timeNow < mStartFromZeroUs + k1SecUs) { // within first second of starting
const int64_t timestampTimeUs = convertTimespecToUs(timestamp.mTime);
- if (timestampTimeUs < mStartUs) {
+ if (timestampTimeUs < mStartFromZeroUs) {
return WOULD_BLOCK; // stale timestamp time, occurs before start.
}
- const int64_t deltaTimeUs = timestampTimeUs - mStartUs;
+ const int64_t deltaTimeUs = timestampTimeUs - mStartFromZeroUs;
const int64_t deltaPositionByUs = (double)timestamp.mPosition * 1000000
/ ((double)mSampleRate * mPlaybackRate.mSpeed);
@@ -2649,10 +2660,10 @@
return WOULD_BLOCK;
}
if (deltaPositionByUs != 0) {
- mStartUs = 0; // don't check again, we got valid nonzero position.
+ mStartFromZeroUs = 0; // don't check again, we got valid nonzero position.
}
} else {
- mStartUs = 0; // don't check again, start time expired.
+ mStartFromZeroUs = 0; // don't check again, start time expired.
}
mTimestampStartupGlitchReported = false;
}
@@ -2690,14 +2701,33 @@
// Prevent retrograde motion in timestamp.
// This is sometimes caused by erratic reports of the available space in the ALSA drivers.
if (status == NO_ERROR) {
+ // previousTimestampValid is set to false when starting after a stop or flush.
if (previousTimestampValid) {
const int64_t previousTimeNanos =
audio_utils_ns_from_timespec(&mPreviousTimestamp.mTime);
- const int64_t currentTimeNanos = audio_utils_ns_from_timespec(×tamp.mTime);
+ int64_t currentTimeNanos = audio_utils_ns_from_timespec(×tamp.mTime);
+
+ // Fix stale time when checking timestamp right after start().
+ //
+ // For offload compatibility, use a default lag value here.
+ // Any time discrepancy between this update and the pause timestamp is handled
+ // by the retrograde check afterwards.
+ const int64_t lagNs = int64_t(mAfLatency * 1000000LL);
+ const int64_t limitNs = mStartNs - lagNs;
+ if (currentTimeNanos < limitNs) {
+ ALOGD("correcting timestamp time for pause, "
+ "currentTimeNanos: %lld < limitNs: %lld < mStartNs: %lld",
+ (long long)currentTimeNanos, (long long)limitNs, (long long)mStartNs);
+ timestamp.mTime = convertNsToTimespec(limitNs);
+ currentTimeNanos = limitNs;
+ }
+
+ // retrograde check
if (currentTimeNanos < previousTimeNanos) {
ALOGW("retrograde timestamp time corrected, %lld < %lld",
(long long)currentTimeNanos, (long long)previousTimeNanos);
timestamp.mTime = mPreviousTimestamp.mTime;
+ // currentTimeNanos not used below.
}
// Looking at signed delta will work even when the timestamps
@@ -2907,7 +2937,7 @@
case STATE_STOPPED:
if (isOffloadedOrDirect_l()) {
// check if we have started in the past to return true.
- return mStartUs > 0;
+ return mStartFromZeroUs > 0;
}
// A normal audio track may still be draining, so
// check if stream has ended. This covers fasttrack position
diff --git a/media/libaudioclient/IAudioTrack.cpp b/media/libaudioclient/IAudioTrack.cpp
index 79e864d..adff057 100644
--- a/media/libaudioclient/IAudioTrack.cpp
+++ b/media/libaudioclient/IAudioTrack.cpp
@@ -28,6 +28,8 @@
namespace android {
+using media::VolumeShaper;
+
enum {
GET_CBLK = IBinder::FIRST_CALL_TRANSACTION,
START,
@@ -185,7 +187,7 @@
return nullptr;
}
sp<VolumeShaper::State> state = new VolumeShaper::State;
- status = state->readFromParcel(reply);
+ status = state->readFromParcel(&reply);
if (status != NO_ERROR) {
return nullptr;
}
@@ -263,12 +265,12 @@
status_t status = data.readInt32(&present);
if (status == NO_ERROR && present != 0) {
configuration = new VolumeShaper::Configuration();
- status = configuration->readFromParcel(data);
+ status = configuration->readFromParcel(&data);
}
status = status ?: data.readInt32(&present);
if (status == NO_ERROR && present != 0) {
operation = new VolumeShaper::Operation();
- status = operation->readFromParcel(data);
+ status = operation->readFromParcel(&data);
}
if (status == NO_ERROR) {
status = (status_t)applyVolumeShaper(configuration, operation);
diff --git a/media/libaudioclient/PlayerBase.cpp b/media/libaudioclient/PlayerBase.cpp
index 7868318..b0c68e5 100644
--- a/media/libaudioclient/PlayerBase.cpp
+++ b/media/libaudioclient/PlayerBase.cpp
@@ -22,6 +22,8 @@
namespace android {
+using media::VolumeShaper;
+
//--------------------------------------------------------------------------------------------------
PlayerBase::PlayerBase() : BnPlayer(),
mPanMultiplierL(1.0f), mPanMultiplierR(1.0f),
@@ -117,23 +119,26 @@
//------------------------------------------------------------------------------
// Implementation of IPlayer
-void PlayerBase::start() {
+binder::Status PlayerBase::start() {
ALOGD("PlayerBase::start() from IPlayer");
(void)startWithStatus();
+ return binder::Status::ok();
}
-void PlayerBase::pause() {
+binder::Status PlayerBase::pause() {
ALOGD("PlayerBase::pause() from IPlayer");
(void)pauseWithStatus();
+ return binder::Status::ok();
}
-void PlayerBase::stop() {
+binder::Status PlayerBase::stop() {
ALOGD("PlayerBase::stop() from IPlayer");
(void)stopWithStatus();
+ return binder::Status::ok();
}
-void PlayerBase::setVolume(float vol) {
+binder::Status PlayerBase::setVolume(float vol) {
ALOGD("PlayerBase::setVolume() from IPlayer");
{
Mutex::Autolock _l(mSettingsLock);
@@ -144,9 +149,10 @@
if (status != NO_ERROR) {
ALOGW("PlayerBase::setVolume() error %d", status);
}
+ return binder::Status::fromStatusT(status);
}
-void PlayerBase::setPan(float pan) {
+binder::Status PlayerBase::setPan(float pan) {
ALOGD("PlayerBase::setPan() from IPlayer");
{
Mutex::Autolock _l(mSettingsLock);
@@ -163,22 +169,19 @@
if (status != NO_ERROR) {
ALOGW("PlayerBase::setPan() error %d", status);
}
+ return binder::Status::fromStatusT(status);
}
-void PlayerBase::setStartDelayMs(int32_t delayMs __unused) {
+binder::Status PlayerBase::setStartDelayMs(int32_t delayMs __unused) {
ALOGW("setStartDelay() is not supported");
+ return binder::Status::ok();
}
-void PlayerBase::applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration __unused,
- const sp<VolumeShaper::Operation>& operation __unused) {
+binder::Status PlayerBase::applyVolumeShaper(
+ const VolumeShaper::Configuration& configuration __unused,
+ const VolumeShaper::Operation& operation __unused) {
ALOGW("applyVolumeShaper() is not supported");
-}
-
-status_t PlayerBase::onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
-{
- return BnPlayer::onTransact(code, data, reply, flags);
+ return binder::Status::ok();
}
} // namespace android
diff --git a/media/libaudioclient/TrackPlayerBase.cpp b/media/libaudioclient/TrackPlayerBase.cpp
index 48cd803..0a914fc 100644
--- a/media/libaudioclient/TrackPlayerBase.cpp
+++ b/media/libaudioclient/TrackPlayerBase.cpp
@@ -18,6 +18,8 @@
namespace android {
+using media::VolumeShaper;
+
//--------------------------------------------------------------------------------------------------
TrackPlayerBase::TrackPlayerBase() : PlayerBase(),
mPlayerVolumeL(1.0f), mPlayerVolumeR(1.0f)
@@ -103,18 +105,24 @@
}
-void TrackPlayerBase::applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) {
+binder::Status TrackPlayerBase::applyVolumeShaper(
+ const VolumeShaper::Configuration& configuration,
+ const VolumeShaper::Operation& operation) {
+
+ sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration);
+ sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation);
+
if (mAudioTrack != 0) {
ALOGD("TrackPlayerBase::applyVolumeShaper() from IPlayer");
- VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
+ VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(spConfiguration, spOperation);
if (status < 0) { // a non-negative value is the volume shaper id.
ALOGE("TrackPlayerBase::applyVolumeShaper() failed with status %d", status);
}
+ return binder::Status::fromStatusT(status);
} else {
ALOGD("TrackPlayerBase::applyVolumeShaper()"
- " no AudioTrack for volume control from IPlayer");
+ " no AudioTrack for volume control from IPlayer");
+ return binder::Status::ok();
}
}
diff --git a/media/libaudioclient/aidl/android/media/IPlayer.aidl b/media/libaudioclient/aidl/android/media/IPlayer.aidl
new file mode 100644
index 0000000..a90fcdd
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/IPlayer.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+package android.media;
+
+import android.media.VolumeShaper.Configuration;
+import android.media.VolumeShaper.Operation;
+
+/**
+ * @hide
+ */
+interface IPlayer {
+ oneway void start();
+ oneway void pause();
+ oneway void stop();
+ oneway void setVolume(float vol);
+ oneway void setPan(float pan);
+ oneway void setStartDelayMs(int delayMs);
+ oneway void applyVolumeShaper(in Configuration configuration,
+ in Operation operation);
+}
diff --git a/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl b/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl
new file mode 100644
index 0000000..fd0e60f
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.media.VolumeShaper;
+
+parcelable Configuration cpp_header "media/VolumeShaper.h";
diff --git a/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl b/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl
new file mode 100644
index 0000000..4290d9d
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.media.VolumeShaper;
+
+parcelable Operation cpp_header "media/VolumeShaper.h";
diff --git a/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl b/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl
new file mode 100644
index 0000000..f6a22b8
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package android.media.VolumeShaper;
+
+parcelable State cpp_header "media/VolumeShaper.h";
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index b168fc9..14afc9d 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -744,12 +744,12 @@
status_t setParameters(const String8& keyValuePairs);
/* Sets the volume shaper object */
- VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation);
+ media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation);
/* Gets the volume shaper state */
- sp<VolumeShaper::State> getVolumeShaperState(int id);
+ sp<media::VolumeShaper::State> getVolumeShaperState(int id);
/* Get parameters */
String8 getParameters(const String8& keys);
@@ -1085,8 +1085,10 @@
// reset by stop() but continues monotonically
// after new IAudioTrack to restore mPosition,
// and could be easily widened to uint64_t
- int64_t mStartUs; // the start time after flush or stop.
+ int64_t mStartFromZeroUs; // the start time after flush or stop,
+ // when position should be 0.
// only used for offloaded and direct tracks.
+ int64_t mStartNs; // the time when start() is called.
ExtendedTimestamp mStartEts; // Extended timestamp at start for normal
// AudioTracks.
AudioTimestamp mStartTs; // Timestamp at start for offloaded or direct
@@ -1146,7 +1148,7 @@
// May not match the app selection depending on other
// activity and connected devices.
- sp<VolumeHandler> mVolumeHandler;
+ sp<media::VolumeHandler> mVolumeHandler;
private:
class DeathNotifier : public IBinder::DeathRecipient {
diff --git a/media/libaudioclient/include/media/IAudioTrack.h b/media/libaudioclient/include/media/IAudioTrack.h
index 27a62d6..94afe3c 100644
--- a/media/libaudioclient/include/media/IAudioTrack.h
+++ b/media/libaudioclient/include/media/IAudioTrack.h
@@ -77,12 +77,12 @@
virtual void signal() = 0;
/* Sets the volume shaper */
- virtual VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) = 0;
+ virtual media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation) = 0;
/* gets the volume shaper state */
- virtual sp<VolumeShaper::State> getVolumeShaperState(int id) = 0;
+ virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/media/libaudioclient/include/media/PlayerBase.h b/media/libaudioclient/include/media/PlayerBase.h
index e63090b..e7a8abc 100644
--- a/media/libaudioclient/include/media/PlayerBase.h
+++ b/media/libaudioclient/include/media/PlayerBase.h
@@ -17,35 +17,31 @@
#ifndef __ANDROID_PLAYER_BASE_H__
#define __ANDROID_PLAYER_BASE_H__
-#include <audiomanager/IPlayer.h>
#include <audiomanager/AudioManager.h>
#include <audiomanager/IAudioManager.h>
+#include "android/media/BnPlayer.h"
namespace android {
-class PlayerBase : public BnPlayer
+class PlayerBase : public ::android::media::BnPlayer
{
public:
explicit PlayerBase();
- virtual ~PlayerBase();
+ virtual ~PlayerBase() override;
virtual void destroy() = 0;
//IPlayer implementation
- virtual void start();
- virtual void pause();
- virtual void stop();
- virtual void setVolume(float vol);
- virtual void setPan(float pan);
- virtual void setStartDelayMs(int32_t delayMs);
- virtual void applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) override;
-
- virtual status_t onTransact(
- uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
-
+ virtual binder::Status start() override;
+ virtual binder::Status pause() override;
+ virtual binder::Status stop() override;
+ virtual binder::Status setVolume(float vol) override;
+ virtual binder::Status setPan(float pan) override;
+ virtual binder::Status setStartDelayMs(int32_t delayMs) override;
+ virtual binder::Status applyVolumeShaper(
+ const media::VolumeShaper::Configuration& configuration,
+ const media::VolumeShaper::Operation& operation) override;
status_t startWithStatus();
status_t pauseWithStatus();
diff --git a/media/libaudioclient/include/media/TrackPlayerBase.h b/media/libaudioclient/include/media/TrackPlayerBase.h
index 2d113c0..66e9b3b 100644
--- a/media/libaudioclient/include/media/TrackPlayerBase.h
+++ b/media/libaudioclient/include/media/TrackPlayerBase.h
@@ -32,9 +32,9 @@
virtual void destroy();
//IPlayer implementation
- virtual void applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation);
+ virtual binder::Status applyVolumeShaper(
+ const media::VolumeShaper::Configuration& configuration,
+ const media::VolumeShaper::Operation& operation);
//FIXME move to protected field, so far made public to minimize changes to AudioTrack logic
sp<AudioTrack> mAudioTrack;
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 1717b49..ee9406d 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -429,9 +429,7 @@
size_t ii;
LVM_INT32 temp;
- src += n-1;
- dst += n-1;
- for (ii = n; ii != 0; ii--) {
+ for (ii = 0; ii < n; ii++) {
temp = (LVM_INT32)((*src) * 32768.0f);
if (temp >= 32767) {
*dst = 32767;
@@ -440,8 +438,8 @@
} else {
*dst = (LVM_INT16)temp;
}
- src--;
- dst--;
+ src++;
+ dst++;
}
return;
}
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 3996227..cda3b3a 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -35,6 +35,8 @@
namespace android {
+using media::VolumeShaper;
+
enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_DATA_SOURCE_URL,
@@ -509,7 +511,7 @@
return nullptr;
}
sp<VolumeShaper::State> state = new VolumeShaper::State();
- status = state->readFromParcel(reply);
+ status = state->readFromParcel(&reply);
if (status != NO_ERROR) {
return nullptr;
}
@@ -851,14 +853,14 @@
status_t status = data.readInt32(&present);
if (status == NO_ERROR && present != 0) {
configuration = new VolumeShaper::Configuration();
- status = configuration->readFromParcel(data);
+ status = configuration->readFromParcel(&data);
}
if (status == NO_ERROR) {
status = data.readInt32(&present);
}
if (status == NO_ERROR && present != 0) {
operation = new VolumeShaper::Operation();
- status = operation->readFromParcel(data);
+ status = operation->readFromParcel(&data);
}
if (status == NO_ERROR) {
status = (status_t)applyVolumeShaper(configuration, operation);
diff --git a/media/libmedia/include/media/IMediaPlayer.h b/media/libmedia/include/media/IMediaPlayer.h
index e5a98dd..e657716 100644
--- a/media/libmedia/include/media/IMediaPlayer.h
+++ b/media/libmedia/include/media/IMediaPlayer.h
@@ -91,10 +91,10 @@
virtual status_t getRetransmitEndpoint(struct sockaddr_in* endpoint) = 0;
virtual status_t setNextPlayer(const sp<IMediaPlayer>& next) = 0;
- virtual VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) = 0;
- virtual sp<VolumeShaper::State> getVolumeShaperState(int id) = 0;
+ virtual media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation) = 0;
+ virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) = 0;
// Modular DRM
virtual status_t prepareDrm(const uint8_t uuid[16],
diff --git a/media/libmedia/include/media/mediaplayer.h b/media/libmedia/include/media/mediaplayer.h
index 623c374..cb0a99f 100644
--- a/media/libmedia/include/media/mediaplayer.h
+++ b/media/libmedia/include/media/mediaplayer.h
@@ -266,10 +266,10 @@
status_t setRetransmitEndpoint(const char* addrString, uint16_t port);
status_t setNextMediaPlayer(const sp<MediaPlayer>& player);
- VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation);
- sp<VolumeShaper::State> getVolumeShaperState(int id);
+ media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation);
+ sp<media::VolumeShaper::State> getVolumeShaperState(int id);
// Modular DRM
status_t prepareDrm(const uint8_t uuid[16], const Vector<uint8_t>& drmSessionId);
status_t releaseDrm();
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index efe947a..49101d1 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -48,6 +48,8 @@
namespace android {
+using media::VolumeShaper;
+
MediaPlayer::MediaPlayer()
{
ALOGV("constructor");
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 43881b3..47a147e 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -120,6 +120,8 @@
// key as part of constructor
dst->mPid = this->mPid;
dst->mUid = this->mUid;
+ dst->mPkgName = this->mPkgName;
+ dst->mPkgVersionCode = this->mPkgVersionCode;
dst->mSessionID = this->mSessionID;
dst->mTimestamp = this->mTimestamp;
dst->mFinalized = this->mFinalized;
@@ -201,6 +203,24 @@
return mUid;
}
+MediaAnalyticsItem &MediaAnalyticsItem::setPkgName(AString pkgName) {
+ mPkgName = pkgName;
+ return *this;
+}
+
+AString MediaAnalyticsItem::getPkgName() const {
+ return mPkgName;
+}
+
+MediaAnalyticsItem &MediaAnalyticsItem::setPkgVersionCode(int32_t pkgVersionCode) {
+ mPkgVersionCode = pkgVersionCode;
+ return *this;
+}
+
+int32_t MediaAnalyticsItem::getPkgVersionCode() const {
+ return mPkgVersionCode;
+}
+
// this key is for the overall record -- "codec", "player", "drm", etc
MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
mKey = key;
@@ -263,11 +283,29 @@
i = mPropCount++;
prop = &mProps[i];
prop->setName(name, len);
+ prop->mType = kTypeNone; // make caller set type info
}
return prop;
}
+// used within the summarizers; return whether property existed
+bool MediaAnalyticsItem::removeProp(const char *name) {
+ size_t len = strlen(name);
+ size_t i = findPropIndex(name, len);
+ if (i < mPropCount) {
+ Prop *prop = &mProps[i];
+ clearProp(prop);
+ if (i != mPropCount-1) {
+ // in the middle, bring last one down to fill gap
+ mProps[i] = mProps[mPropCount-1];
+ }
+ mPropCount--;
+ return true;
+ }
+ return false;
+}
+
// set the values
void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
@@ -568,6 +606,10 @@
// into 'this' object
// .. we make a copy of the string to put away.
mKey = data.readCString();
+ mPid = data.readInt32();
+ mUid = data.readInt32();
+ mPkgName = data.readCString();
+ mPkgVersionCode = data.readInt32();
mSessionID = data.readInt64();
mFinalized = data.readInt32();
mTimestamp = data.readInt64();
@@ -611,6 +653,10 @@
data->writeCString(mKey.c_str());
+ data->writeInt32(mPid);
+ data->writeInt32(mUid);
+ data->writeCString(mPkgName.c_str());
+ data->writeInt32(mPkgVersionCode);
data->writeInt64(mSessionID);
data->writeInt32(mFinalized);
data->writeInt64(mTimestamp);
@@ -651,21 +697,54 @@
AString MediaAnalyticsItem::toString() {
+ return toString(-1);
+}
- AString result = "(";
+AString MediaAnalyticsItem::toString(int version) {
+
+ // v0 : released with 'o'
+ // v1 : bug fix (missing pid/finalized separator),
+ // adds apk name, apk version code
+
+ if (version <= PROTO_FIRST) {
+ // default to original v0 format, until proper parsers are in place
+ version = PROTO_V0;
+ } else if (version > PROTO_LAST) {
+ version = PROTO_LAST;
+ }
+
+ AString result;
char buffer[512];
+ if (version == PROTO_V0) {
+ result = "(";
+ } else {
+ snprintf(buffer, sizeof(buffer), "[%d:", version);
+ result.append(buffer);
+ }
+
// same order as we spill into the parcel, although not required
// key+session are our primary matching criteria
- //RBE ALOGD("mKey.c_str");
result.append(mKey.c_str());
- //RBE ALOGD("post-mKey.c_str");
result.append(":");
snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
result.append(buffer);
- // we need these internally, but don't want to upload them
- snprintf(buffer, sizeof(buffer), "%d:%d", mUid, mPid);
+ snprintf(buffer, sizeof(buffer), "%d:", mUid);
+ result.append(buffer);
+
+ if (version >= PROTO_V1) {
+ result.append(mPkgName);
+ snprintf(buffer, sizeof(buffer), ":%d:", mPkgVersionCode);
+ result.append(buffer);
+ }
+
+ // in 'o' (v1) , the separator between pid and finalized was omitted
+ if (version <= PROTO_V0) {
+ snprintf(buffer, sizeof(buffer), "%d", mPid);
+ } else {
+ snprintf(buffer, sizeof(buffer), "%d:", mPid);
+ }
result.append(buffer);
snprintf(buffer, sizeof(buffer), "%d:", mFinalized);
@@ -713,7 +792,11 @@
result.append(buffer);
}
- result.append(")");
+ if (version == PROTO_V0) {
+ result.append(")");
+ } else {
+ result.append("]");
+ }
return result;
}
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index dc501b2..41b9658 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -75,6 +75,14 @@
typedef const char *Attr;
+ enum {
+ PROTO_V0 = 0,
+ PROTO_FIRST = PROTO_V0,
+ PROTO_V1 = 1,
+ PROTO_LAST = PROTO_V1,
+ };
+
+
public:
// access functions for the class
@@ -161,11 +169,18 @@
MediaAnalyticsItem &setUid(uid_t);
uid_t getUid() const;
+ MediaAnalyticsItem &setPkgName(AString);
+ AString getPkgName() const;
+
+ MediaAnalyticsItem &setPkgVersionCode(int32_t);
+ int32_t getPkgVersionCode() const;
+
// our serialization code for binder calls
int32_t writeToParcel(Parcel *);
int32_t readFromParcel(const Parcel&);
AString toString();
+ AString toString(int version);
// are we collecting analytics data
static bool isEnabled();
@@ -188,6 +203,8 @@
// to help validate that A doesn't mess with B's records
pid_t mPid;
uid_t mUid;
+ AString mPkgName;
+ int32_t mPkgVersionCode;
// let's reuse a binder connection
static sp<IMediaAnalyticsService> sAnalyticsService;
@@ -228,6 +245,7 @@
size_t findPropIndex(const char *name, size_t len);
Prop *findProp(const char *name);
Prop *allocateProp(const char *name);
+ bool removeProp(const char *name);
size_t mPropCount;
size_t mPropSize;
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index 496db0d..ba98f18 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -93,6 +93,7 @@
using android::BAD_VALUE;
using android::NOT_ENOUGH_DATA;
using android::Parcel;
+using android::media::VolumeShaper;
// Max number of entries in the filter.
const int kMaxFilterSize = 64; // I pulled that out of thin air.
@@ -1577,7 +1578,7 @@
mSendLevel(0.0),
mAuxEffectId(0),
mFlags(AUDIO_OUTPUT_FLAG_NONE),
- mVolumeHandler(new VolumeHandler())
+ mVolumeHandler(new media::VolumeHandler())
{
ALOGV("AudioOutput(%d)", sessionId);
if (attr != NULL) {
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index 06b9cad..25691f9 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -132,10 +132,10 @@
virtual status_t setParameters(const String8& keyValuePairs);
virtual String8 getParameters(const String8& keys);
- virtual VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) override;
- virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+ virtual media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation) override;
+ virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
private:
static void setMinBufferCount();
@@ -165,7 +165,7 @@
float mSendLevel;
int mAuxEffectId;
audio_output_flags_t mFlags;
- sp<VolumeHandler> mVolumeHandler;
+ sp<media::VolumeHandler> mVolumeHandler;
mutable Mutex mLock;
// static variables below not protected by mutex
@@ -343,10 +343,10 @@
virtual status_t getRetransmitEndpoint(struct sockaddr_in* endpoint);
virtual status_t setNextPlayer(const sp<IMediaPlayer>& player);
- virtual VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) override;
- virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+ virtual media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation) override;
+ virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
sp<MediaPlayerBase> createPlayer(player_type playerType);
diff --git a/media/libmediaplayerservice/include/MediaPlayerInterface.h b/media/libmediaplayerservice/include/MediaPlayerInterface.h
index e8d59a7..bcdca37 100644
--- a/media/libmediaplayerservice/include/MediaPlayerInterface.h
+++ b/media/libmediaplayerservice/include/MediaPlayerInterface.h
@@ -146,10 +146,10 @@
virtual status_t setParameters(const String8& /* keyValuePairs */) { return NO_ERROR; }
virtual String8 getParameters(const String8& /* keys */) { return String8::empty(); }
- virtual VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation);
- virtual sp<VolumeShaper::State> getVolumeShaperState(int id);
+ virtual media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation);
+ virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id);
};
MediaPlayerBase() : mCookie(0), mNotify(0) {}
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index df36046..274f613 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -49,6 +49,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
@@ -172,9 +173,10 @@
////////////////////////////////////////////////////////////////////////////////
-NuPlayer::NuPlayer(pid_t pid)
+NuPlayer::NuPlayer(pid_t pid, const sp<MediaClock> &mediaClock)
: mUIDValid(false),
mPID(pid),
+ mMediaClock(mediaClock),
mSourceFlags(0),
mOffloadAudio(false),
mAudioDecoderGeneration(0),
@@ -204,6 +206,7 @@
mPausedForBuffering(false),
mIsDrmProtected(false),
mDataSourceType(DATA_SOURCE_TYPE_NONE) {
+ CHECK(mediaClock != NULL);
clearFlushComplete();
}
@@ -1523,7 +1526,7 @@
sp<AMessage> notify = new AMessage(kWhatRendererNotify, this);
++mRendererGeneration;
notify->setInt32("generation", mRendererGeneration);
- mRenderer = new Renderer(mAudioSink, notify, flags);
+ mRenderer = new Renderer(mAudioSink, mMediaClock, notify, flags);
mRendererLooper = new ALooper;
mRendererLooper->setName("NuPlayerRenderer");
mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index c69835f..5e3c48b 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -30,11 +30,12 @@
struct AudioPlaybackRate;
struct AVSyncSettings;
class IDataSource;
+struct MediaClock;
class MetaData;
struct NuPlayerDriver;
struct NuPlayer : public AHandler {
- explicit NuPlayer(pid_t pid);
+ explicit NuPlayer(pid_t pid, const sp<MediaClock> &mediaClock);
void setUID(uid_t uid);
@@ -157,6 +158,7 @@
bool mUIDValid;
uid_t mUID;
pid_t mPID;
+ const sp<MediaClock> mMediaClock;
Mutex mSourceLock; // guard |mSource|.
sp<Source> mSource;
uint32_t mSourceFlags;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 0fc1aa7..209caeb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -28,6 +28,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AUtils.h>
+#include <media/stagefright/MediaClock.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/Utils.h>
@@ -66,15 +67,19 @@
mSeekInProgress(false),
mPlayingTimeUs(0),
mLooper(new ALooper),
- mPlayer(new NuPlayer(pid)),
+ mMediaClock(new MediaClock),
+ mPlayer(new NuPlayer(pid, mMediaClock)),
mPlayerFlags(0),
mAnalyticsItem(NULL),
+ mClientUid(-1),
mAtEOS(false),
mLooping(false),
mAutoLoop(false) {
ALOGD("NuPlayerDriver(%p) created, clientPid(%d)", this, pid);
mLooper->setName("NuPlayerDriver Looper");
+ mMediaClock->init();
+
// set up an analytics record
mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
mAnalyticsItem->generateSessionID();
@@ -109,6 +114,10 @@
status_t NuPlayerDriver::setUID(uid_t uid) {
mPlayer->setUID(uid);
+ mClientUid = uid;
+ if (mAnalyticsItem) {
+ mAnalyticsItem->setUid(mClientUid);
+ }
return OK;
}
@@ -601,6 +610,7 @@
mAnalyticsItem = new MediaAnalyticsItem("nuplayer");
if (mAnalyticsItem) {
mAnalyticsItem->generateSessionID();
+ mAnalyticsItem->setUid(mClientUid);
}
} else {
ALOGV("did not have anything to record");
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
index c5ddcb0..b797ca1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.h
@@ -22,6 +22,7 @@
namespace android {
struct ALooper;
+struct MediaClock;
struct NuPlayer;
struct NuPlayerDriver : public MediaPlayerInterface {
@@ -127,16 +128,19 @@
// <<<
sp<ALooper> mLooper;
+ const sp<MediaClock> mMediaClock;
const sp<NuPlayer> mPlayer;
sp<AudioSink> mAudioSink;
uint32_t mPlayerFlags;
MediaAnalyticsItem *mAnalyticsItem;
+ uid_t mClientUid;
bool mAtEOS;
bool mLooping;
bool mAutoLoop;
+
void updateMetrics(const char *where);
void logMetrics(const char *where);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 390b042..dec17e2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -89,6 +89,7 @@
NuPlayer::Renderer::Renderer(
const sp<MediaPlayerBase::AudioSink> &sink,
+ const sp<MediaClock> &mediaClock,
const sp<AMessage> ¬ify,
uint32_t flags)
: mAudioSink(sink),
@@ -103,6 +104,7 @@
mAudioDrainGeneration(0),
mVideoDrainGeneration(0),
mAudioEOSGeneration(0),
+ mMediaClock(mediaClock),
mPlaybackSettings(AUDIO_PLAYBACK_RATE_DEFAULT),
mAudioFirstAnchorTimeMediaUs(-1),
mAnchorTimeMediaUs(-1),
@@ -130,7 +132,7 @@
mLastAudioBufferDrained(0),
mUseAudioCallback(false),
mWakeLock(new AWakeLock()) {
- mMediaClock = new MediaClock;
+ CHECK(mediaClock != NULL);
mPlaybackRate = mPlaybackSettings.mSpeed;
mMediaClock->setPlaybackRate(mPlaybackRate);
}
@@ -149,7 +151,6 @@
flushQueue(&mVideoQueue);
}
mWakeLock.clear();
- mMediaClock.clear();
mVideoScheduler.clear();
mNotify.clear();
mAudioSink.clear();
@@ -1152,7 +1153,18 @@
return writtenAudioDurationUs - (mediaUs - mAudioFirstAnchorTimeMediaUs);
}
}
- return writtenAudioDurationUs - mAudioSink->getPlayedOutDurationUs(nowUs);
+
+ const int64_t audioSinkPlayedUs = mAudioSink->getPlayedOutDurationUs(nowUs);
+ int64_t pendingUs = writtenAudioDurationUs - audioSinkPlayedUs;
+ if (pendingUs < 0) {
+ // This shouldn't happen unless the timestamp is stale.
+ ALOGW("%s: pendingUs %lld < 0, clamping to zero, potential resume after pause "
+ "writtenAudioDurationUs: %lld, audioSinkPlayedUs: %lld",
+ __func__, (long long)pendingUs,
+ (long long)writtenAudioDurationUs, (long long)audioSinkPlayedUs);
+ pendingUs = 0;
+ }
+ return pendingUs;
}
int64_t NuPlayer::Renderer::getRealTimeUs(int64_t mediaTimeUs, int64_t nowUs) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index f58b79c..567f8f1 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -36,6 +36,7 @@
FLAG_OFFLOAD_AUDIO = 2,
};
Renderer(const sp<MediaPlayerBase::AudioSink> &sink,
+ const sp<MediaClock> &mediaClock,
const sp<AMessage> ¬ify,
uint32_t flags = 0);
@@ -165,7 +166,7 @@
int32_t mVideoDrainGeneration;
int32_t mAudioEOSGeneration;
- sp<MediaClock> mMediaClock;
+ const sp<MediaClock> mMediaClock;
float mPlaybackRate; // audio track rate
AudioPlaybackRate mPlaybackSettings;
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 0e60b2e..ec48561 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -4322,9 +4322,14 @@
h264type.bUseHadamard = OMX_TRUE;
h264type.nRefFrames = 2;
h264type.nBFrames = mLatency == 0 ? 1 : std::min(1U, mLatency - 1);
+
+ // disable B-frames until MPEG4Writer can guarantee finalizing files with B-frames
+ h264type.nRefFrames = 1;
+ h264type.nBFrames = 0;
+
h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate, h264type.nBFrames);
h264type.nAllowedPictureTypes =
- OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP | OMX_VIDEO_PictureTypeB;
+ OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
h264type.nRefIdx10ActiveMinus1 = 0;
h264type.nRefIdx11ActiveMinus1 = 0;
h264type.bEntropyCodingCABAC = OMX_TRUE;
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 5ef0f56..6f59fac 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -5224,6 +5224,7 @@
void MPEG4Extractor::populateMetrics() {
ALOGV("MPEG4Extractor::populateMetrics");
+ // write into mAnalyticsItem
}
static bool LegacySniffMPEG4(
diff --git a/media/libstagefright/MediaClock.cpp b/media/libstagefright/MediaClock.cpp
index 3aa0061..669e09b 100644
--- a/media/libstagefright/MediaClock.cpp
+++ b/media/libstagefright/MediaClock.cpp
@@ -21,7 +21,7 @@
#include <media/stagefright/MediaClock.h>
#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
namespace android {
@@ -34,10 +34,41 @@
mAnchorTimeRealUs(-1),
mMaxTimeMediaUs(INT64_MAX),
mStartingTimeMediaUs(-1),
- mPlaybackRate(1.0) {
+ mPlaybackRate(1.0),
+ mGeneration(0) {
+ mLooper = new ALooper;
+ mLooper->setName("MediaClock");
+ mLooper->start(false /* runOnCallingThread */,
+ false /* canCallJava */,
+ ANDROID_PRIORITY_AUDIO);
+}
+
+void MediaClock::init() {
+ mLooper->registerHandler(this);
}
MediaClock::~MediaClock() {
+ reset();
+ if (mLooper != NULL) {
+ mLooper->unregisterHandler(id());
+ mLooper->stop();
+ }
+}
+
+void MediaClock::reset() {
+ Mutex::Autolock autoLock(mLock);
+ auto it = mTimers.begin();
+ while (it != mTimers.end()) {
+ it->second->setInt32("reason", TIMER_REASON_RESET);
+ it->second->post();
+ it = mTimers.erase(it);
+ }
+ mAnchorTimeMediaUs = -1;
+ mAnchorTimeRealUs = -1;
+ mMaxTimeMediaUs = INT64_MAX;
+ mStartingTimeMediaUs = -1;
+ mPlaybackRate = 1.0;
+ ++mGeneration;
}
void MediaClock::setStartingTimeMedia(int64_t startingTimeMediaUs) {
@@ -82,6 +113,9 @@
}
mAnchorTimeRealUs = nowUs;
mAnchorTimeMediaUs = nowMediaUs;
+
+ ++mGeneration;
+ processTimers_l();
}
void MediaClock::updateMaxTimeMedia(int64_t maxTimeMediaUs) {
@@ -105,6 +139,11 @@
}
mAnchorTimeRealUs = nowUs;
mPlaybackRate = rate;
+
+ if (rate > 0.0) {
+ ++mGeneration;
+ processTimers_l();
+ }
}
float MediaClock::getPlaybackRate() const {
@@ -165,4 +204,64 @@
return OK;
}
+void MediaClock::addTimer(const sp<AMessage> ¬ify, int64_t mediaTimeUs) {
+ Mutex::Autolock autoLock(mLock);
+ int64_t nextMediaTimeUs = INT64_MAX;
+ if (!mTimers.empty()) {
+ nextMediaTimeUs = mTimers.begin()->first;
+ }
+
+ mTimers.emplace(mediaTimeUs, notify);
+ if (mediaTimeUs < nextMediaTimeUs) {
+ ++mGeneration;
+ processTimers_l();
+ }
+}
+
+void MediaClock::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatTimeIsUp:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ Mutex::Autolock autoLock(mLock);
+ if (generation != mGeneration) {
+ break;
+ }
+ processTimers_l();
+ break;
+ }
+
+ default:
+ TRESPASS();
+ break;
+ }
+}
+
+void MediaClock::processTimers_l() {
+ int64_t nowMediaTimeUs;
+ status_t status = getMediaTime_l(
+ ALooper::GetNowUs(), &nowMediaTimeUs, false /* allowPastMaxTime */);
+
+ if (status != OK) {
+ return;
+ }
+
+ auto it = mTimers.begin();
+ while (it != mTimers.end() && it->first <= nowMediaTimeUs) {
+ it->second->setInt32("reason", TIMER_REASON_REACHED);
+ it->second->post();
+ it = mTimers.erase(it);
+ }
+
+ if (it == mTimers.end() || mPlaybackRate == 0.0 || mAnchorTimeMediaUs < 0) {
+ return;
+ }
+
+ sp<AMessage> msg = new AMessage(kWhatTimeIsUp, this);
+ msg->setInt32("generation", mGeneration);
+ msg->post((it->first - nowMediaTimeUs) / (double)mPlaybackRate);
+}
+
} // namespace android
diff --git a/media/libstagefright/MediaSync.cpp b/media/libstagefright/MediaSync.cpp
index 9278381..ba14e5d 100644
--- a/media/libstagefright/MediaSync.cpp
+++ b/media/libstagefright/MediaSync.cpp
@@ -61,6 +61,7 @@
mNextBufferItemMediaUs(-1),
mPlaybackRate(0.0) {
mMediaClock = new MediaClock;
+ mMediaClock->init();
// initialize settings
mPlaybackSettings = AUDIO_PLAYBACK_RATE_DEFAULT;
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index caceda9..56d2d69 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -154,6 +154,30 @@
ALOGV("SoftFlacEncoder::internalGetParameter(index=0x%x)", index);
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if (formatParams->nIndex > 0) {
+ return OMX_ErrorNoMore;
+ }
+
+ formatParams->eEncoding =
+ (formatParams->nPortIndex == 0)
+ ? OMX_AUDIO_CodingPCM : OMX_AUDIO_CodingFLAC;
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
@@ -163,7 +187,7 @@
return OMX_ErrorBadParameter;
}
- if (pcmParams->nPortIndex > 1) {
+ if (pcmParams->nPortIndex != 0) {
return OMX_ErrorUndefined;
}
@@ -189,6 +213,10 @@
return OMX_ErrorBadParameter;
}
+ if (flacParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
flacParams->nCompressionLevel = mCompressionLevel;
flacParams->nChannels = mNumChannels;
flacParams->nSampleRate = mSampleRate;
@@ -203,6 +231,29 @@
OMX_ERRORTYPE SoftFlacEncoder::internalSetParameter(
OMX_INDEXTYPE index, const OMX_PTR params) {
switch (index) {
+ case OMX_IndexParamAudioPortFormat:
+ {
+ const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
+ (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
+
+ if (!isValidOMXParam(formatParams)) {
+ return OMX_ErrorBadParameter;
+ }
+
+ if (formatParams->nPortIndex > 1) {
+ return OMX_ErrorUndefined;
+ }
+
+ if ((formatParams->nPortIndex == 0
+ && formatParams->eEncoding != OMX_AUDIO_CodingPCM)
+ || (formatParams->nPortIndex == 1
+ && formatParams->eEncoding != OMX_AUDIO_CodingFLAC)) {
+ return OMX_ErrorUndefined;
+ }
+
+ return OMX_ErrorNone;
+ }
+
case OMX_IndexParamAudioPcm:
{
ALOGV("SoftFlacEncoder::internalSetParameter(OMX_IndexParamAudioPcm)");
@@ -212,7 +263,7 @@
return OMX_ErrorBadParameter;
}
- if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
+ if (pcmParams->nPortIndex != 0) {
ALOGE("SoftFlacEncoder::internalSetParameter() Error #1");
return OMX_ErrorUndefined;
}
@@ -258,6 +309,10 @@
return OMX_ErrorBadParameter;
}
+ if (flacParams->nPortIndex != 1) {
+ return OMX_ErrorUndefined;
+ }
+
mCompressionLevel = flacParams->nCompressionLevel; // range clamping done inside encoder
return OMX_ErrorNone;
}
diff --git a/media/libstagefright/foundation/base64.cpp b/media/libstagefright/foundation/base64.cpp
index cc89064..8f32582 100644
--- a/media/libstagefright/foundation/base64.cpp
+++ b/media/libstagefright/foundation/base64.cpp
@@ -23,6 +23,7 @@
sp<ABuffer> decodeBase64(const AString &s) {
size_t n = s.size();
+
if ((n % 4) != 0) {
return NULL;
}
@@ -45,7 +46,6 @@
size_t outLen = (n / 4) * 3 - padding;
sp<ABuffer> buffer = new ABuffer(outLen);
-
uint8_t *out = buffer->data();
if (out == NULL || buffer->size() < outLen) {
return NULL;
@@ -61,9 +61,9 @@
value = 26 + c - 'a';
} else if (c >= '0' && c <= '9') {
value = 52 + c - '0';
- } else if (c == '+') {
+ } else if (c == '+' || c == '-') {
value = 62;
- } else if (c == '/') {
+ } else if (c == '/' || c == '_') {
value = 63;
} else if (c != '=') {
return NULL;
@@ -144,4 +144,26 @@
}
}
+void encodeBase64Url(
+ const void *_data, size_t size, AString *out) {
+ encodeBase64(_data, size, out);
+
+ if ((-1 != out->find("+")) || (-1 != out->find("/"))) {
+ size_t outLen = out->size();
+ char *base64url = new char[outLen];
+ for (size_t i = 0; i < outLen; ++i) {
+ if (out->c_str()[i] == '+')
+ base64url[i] = '-';
+ else if (out->c_str()[i] == '/')
+ base64url[i] = '_';
+ else
+ base64url[i] = out->c_str()[i];
+ }
+
+ out->setTo(base64url, outLen);
+ delete[] base64url;
+ }
+}
+
+
} // namespace android
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
index e340b89..abc95e0 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/base64.h
@@ -28,6 +28,8 @@
sp<ABuffer> decodeBase64(const AString &s);
void encodeBase64(const void *data, size_t size, AString *out);
+void encodeBase64Url(const void *data, size_t size, AString *out);
+
} // namespace android
#endif // BASE_64_H_
diff --git a/media/libstagefright/foundation/tests/Android.mk b/media/libstagefright/foundation/tests/Android.mk
index d741c6f..a9e3c76 100644
--- a/media/libstagefright/foundation/tests/Android.mk
+++ b/media/libstagefright/foundation/tests/Android.mk
@@ -9,11 +9,13 @@
LOCAL_SRC_FILES := \
AData_test.cpp \
+ Base64_test.cpp \
Flagged_test.cpp \
TypeTraits_test.cpp \
Utils_test.cpp \
LOCAL_SHARED_LIBRARIES := \
+ liblog \
libstagefright_foundation \
libutils \
diff --git a/media/libstagefright/foundation/tests/Base64_test.cpp b/media/libstagefright/foundation/tests/Base64_test.cpp
new file mode 100644
index 0000000..7a4289e
--- /dev/null
+++ b/media/libstagefright/foundation/tests/Base64_test.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <utils/Log.h>
+
+#include "gtest/gtest.h"
+
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/foundation/AStringUtils.h>
+#include <media/stagefright/foundation/base64.h>
+
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace {
+const android::String8 kBase64Padding("=");
+};
+
+namespace android {
+
+class Base64Test : public ::testing::Test {
+};
+
+void verifyDecode(const AString* expected, const AString* in) {
+ size_t numTests = 0;
+ while (!expected[numTests].empty())
+ ++numTests;
+
+ for (size_t i = 0; i < numTests; ++i) {
+ // Since android::decodeBase64() requires padding characters,
+ // add them so length of encoded text is exactly a multiple of 4.
+ int remainder = in[i].size() % 4;
+ String8 paddedText(in[i].c_str());
+ if (remainder > 0) {
+ for (int i = 0; i < 4 - remainder; ++i) {
+ paddedText.append(kBase64Padding);
+ }
+ }
+ sp<ABuffer> result = decodeBase64(AString(paddedText.string()));
+
+ ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(),
+ reinterpret_cast<char*>(result->data()),
+ expected[i].size(), false), 0);
+ }
+}
+
+void verifyEncode(const AString* expected, const AString* in) {
+ size_t numTests = 0;
+ while (!expected[numTests].empty())
+ ++numTests;
+
+ AString out = AString("");
+ for (size_t i = 0; i < numTests; ++i) {
+ encodeBase64Url(in[i].c_str(), in[i].size(), &out);
+
+ ASSERT_EQ(AStringUtils::Compare(expected[i].c_str(), out.c_str(),
+ expected[i].size(), false), 0);
+ }
+}
+
+TEST_F(Base64Test, TestDecodeBase64) {
+ const AString base64[] = {
+ AString("SGVsbG8gRnJpZW5kIQ"),
+ AString("R29vZCBkYXkh"),
+ AString("") // string to signal end of array
+ };
+
+ const AString clearText[] = {
+ AString("Hello Friend!"),
+ AString("Good day!"),
+ AString("")
+ };
+
+ verifyDecode(clearText, base64);
+}
+
+TEST_F(Base64Test, TestDecodeBase64Url) {
+ const AString base64Url[] = {
+ AString("SGVsbG8gRnJpZW5kICE-Pw"),
+ AString("SGVsbG8gRnJpZW5kICE_"),
+ AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
+ AString("")
+ };
+
+ const AString clearText[] = {
+ AString("Hello Friend !>?"),
+ AString("Hello Friend !?"),
+ AString("Hello ?>> Friend ?>"),
+ AString("")
+ };
+
+ verifyDecode(clearText, base64Url);
+}
+
+TEST_F(Base64Test, TestDecodeMalformedBase64) {
+ const AString base64Url[] = {
+ AString("1?GawgguFyGrWKav7AX4VKUg"), // fail on parsing
+ AString("GawgguFyGrWKav7AX4V???"), // fail on length not multiple of 4
+ AString("GawgguFyGrWKav7AX4VKUg"), // ditto
+ };
+
+ for (size_t i = 0; i < 3; ++i) {
+ sp<ABuffer> result = decodeBase64(AString(base64Url[i]));
+ EXPECT_TRUE(result == nullptr);
+ }
+}
+
+TEST_F(Base64Test, TestEncodeBase64) {
+ const AString clearText[] = {
+ AString("Hello Friend!"),
+ AString("Good day!"),
+ AString("")
+ };
+
+ const AString base64[] = {
+ AString("SGVsbG8gRnJpZW5kIQ=="),
+ AString("R29vZCBkYXkh"),
+ AString("")
+ };
+
+ verifyEncode(base64, clearText);
+}
+
+TEST_F(Base64Test, TestEncodeBase64Url) {
+ const AString clearText[] = {
+ AString("Hello Friend !>?"),
+ AString("Hello Friend !?"),
+ AString("Hello ?>> Friend ?>"),
+ AString("")
+ };
+
+ const AString base64Url[] = {
+ AString("SGVsbG8gRnJpZW5kICE-Pw=="),
+ AString("SGVsbG8gRnJpZW5kICE_"),
+ AString("SGVsbG8gPz4-IEZyaWVuZCA_Pg"),
+ AString("")
+ };
+
+ verifyEncode(base64Url, clearText);
+}
+
+} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaClock.h b/media/libstagefright/include/media/stagefright/MediaClock.h
index dd1a809..59f700a 100644
--- a/media/libstagefright/include/media/stagefright/MediaClock.h
+++ b/media/libstagefright/include/media/stagefright/MediaClock.h
@@ -18,7 +18,8 @@
#define MEDIA_CLOCK_H_
-#include <media/stagefright/foundation/ABase.h>
+#include <map>
+#include <media/stagefright/foundation/AHandler.h>
#include <utils/Mutex.h>
#include <utils/RefBase.h>
@@ -26,8 +27,15 @@
struct AMessage;
-struct MediaClock : public RefBase {
+struct MediaClock : public AHandler {
+ enum {
+ TIMER_REASON_REACHED = 0,
+ TIMER_REASON_NO_CLOCK = 1,
+ TIMER_REASON_RESET = 2,
+ };
+
MediaClock();
+ void init();
void setStartingTimeMedia(int64_t startingTimeMediaUs);
@@ -54,15 +62,28 @@
// The result is saved in |outRealUs|.
status_t getRealTimeFor(int64_t targetMediaUs, int64_t *outRealUs) const;
+ void addTimer(const sp<AMessage> ¬ify, int64_t mediaTimeUs);
+
+ void reset();
+
protected:
virtual ~MediaClock();
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
private:
+ enum {
+ kWhatTimeIsUp = 'tIsU',
+ };
+
status_t getMediaTime_l(
int64_t realUs,
int64_t *outMediaUs,
bool allowPastMaxTime) const;
+ void processTimers_l();
+
+ sp<ALooper> mLooper;
mutable Mutex mLock;
int64_t mAnchorTimeMediaUs;
@@ -72,6 +93,9 @@
float mPlaybackRate;
+ int32_t mGeneration;
+ std::multimap<int64_t, sp<AMessage> > mTimers;
+
DISALLOW_EVIL_CONSTRUCTORS(MediaClock);
};
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 813a257..4b38906 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -140,6 +140,7 @@
enum Type {
AVC,
AAC,
+ HEVC,
OTHER
};
@@ -148,7 +149,7 @@
Type mType;
bool mIsAudio;
BlockIterator mBlockIter;
- ssize_t mNALSizeLen; // for type AVC
+ ssize_t mNALSizeLen; // for type AVC or HEVC
List<MediaBuffer *> mPendingFrames;
@@ -244,6 +245,19 @@
} else {
ALOGE("No mNALSizeLen");
}
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_HEVC)) {
+ mType = HEVC;
+
+ uint32_t dummy;
+ const uint8_t *hvcc;
+ size_t hvccSize;
+ if (meta->findData(kKeyHVCC, &dummy, (const void **)&hvcc, &hvccSize)
+ && hvccSize >= 22u) {
+ mNALSizeLen = 1 + (hvcc[14+7] & 3);
+ ALOGV("mNALSizeLen = %zu", mNALSizeLen);
+ } else {
+ ALOGE("No mNALSizeLen");
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
mType = AAC;
}
@@ -692,7 +706,7 @@
MediaBuffer *frame = *mPendingFrames.begin();
mPendingFrames.erase(mPendingFrames.begin());
- if (mType != AVC || mNALSizeLen == 0) {
+ if ((mType != AVC && mType != HEVC) || mNALSizeLen == 0) {
if (targetSampleTimeUs >= 0ll) {
frame->meta_data()->setInt64(
kKeyTargetTime, targetSampleTimeUs);
@@ -1293,6 +1307,14 @@
if (!strcmp("V_MPEG4/ISO/AVC", codecID)) {
meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
meta->setData(kKeyAVCC, 0, codecPrivate, codecPrivateSize);
+ } else if (!strcmp("V_MPEGH/ISO/HEVC", codecID)) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_HEVC);
+ if (codecPrivateSize > 0) {
+ meta->setData(kKeyHVCC, kTypeHVCC, codecPrivate, codecPrivateSize);
+ } else {
+ ALOGW("HEVC is detected, but does not have configuration.");
+ continue;
+ }
} else if (!strcmp("V_MPEG4/ISO/ASP", codecID)) {
if (codecPrivateSize > 0) {
meta->setCString(
diff --git a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
index fcf1092..c4499dc 100644
--- a/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
+++ b/media/libstagefright/omx/1.0/WGraphicBufferProducer.cpp
@@ -41,7 +41,9 @@
sp<GraphicBuffer> buf;
status_t status = mBase->requestBuffer(slot, &buf);
AnwBuffer anwBuffer;
- wrapAs(&anwBuffer, *buf);
+ if (buf != nullptr) {
+ wrapAs(&anwBuffer, *buf);
+ }
_hidl_cb(static_cast<int32_t>(status), anwBuffer);
return Void();
}
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index bb05740..46f2dd1 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -65,6 +65,7 @@
"libhidlmemory",
"libhidltransport",
"libnativewindow", // TODO(b/62923479): use header library
+ "libvndksupport",
"android.hidl.memory@1.0",
"android.hidl.token@1.0-utils",
"android.hardware.media@1.0",
diff --git a/media/libstagefright/omx/OMXMaster.cpp b/media/libstagefright/omx/OMXMaster.cpp
index fd97fdc..0967b5f 100644
--- a/media/libstagefright/omx/OMXMaster.cpp
+++ b/media/libstagefright/omx/OMXMaster.cpp
@@ -22,6 +22,8 @@
#include <media/stagefright/omx/SoftOMXPlugin.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <vndksupport/linker.h>
+
#include <dlfcn.h>
#include <fcntl.h>
@@ -67,7 +69,7 @@
}
void OMXMaster::addPlugin(const char *libname) {
- mVendorLibHandle = dlopen(libname, RTLD_NOW);
+ mVendorLibHandle = android_load_sphal_library(libname, RTLD_NOW);
if (mVendorLibHandle == NULL) {
return;
diff --git a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
index f319bdc..8d8a2d9 100644
--- a/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
+++ b/media/libstagefright/omx/include/media/stagefright/omx/1.0/Conversion.h
@@ -2064,8 +2064,10 @@
int const* constFds = static_cast<int const*>(baseFds.get());
numFds = baseNumFds;
if (l->unflatten(constBuffer, size, constFds, numFds) != NO_ERROR) {
- native_handle_close(nh);
- native_handle_delete(nh);
+ if (nh != nullptr) {
+ native_handle_close(nh);
+ native_handle_delete(nh);
+ }
return false;
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1b7d875..de617b9 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -557,10 +557,10 @@
virtual void pause();
virtual status_t attachAuxEffect(int effectId);
virtual status_t setParameters(const String8& keyValuePairs);
- virtual VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation) override;
- virtual sp<VolumeShaper::State> getVolumeShaperState(int id) override;
+ virtual media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation) override;
+ virtual sp<media::VolumeShaper::State> getVolumeShaperState(int id) override;
virtual status_t getTimestamp(AudioTimestamp& timestamp);
virtual void signal(); // signal playback thread for a change in control block
diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h
index 1c1a989..946d88f 100644
--- a/services/audioflinger/PlaybackTracks.h
+++ b/services/audioflinger/PlaybackTracks.h
@@ -82,11 +82,11 @@
virtual bool isFastTrack() const { return (mFlags & AUDIO_OUTPUT_FLAG_FAST) != 0; }
// implement volume handling.
- VolumeShaper::Status applyVolumeShaper(
- const sp<VolumeShaper::Configuration>& configuration,
- const sp<VolumeShaper::Operation>& operation);
-sp<VolumeShaper::State> getVolumeShaperState(int id);
- sp<VolumeHandler> getVolumeHandler() { return mVolumeHandler; }
+ media::VolumeShaper::Status applyVolumeShaper(
+ const sp<media::VolumeShaper::Configuration>& configuration,
+ const sp<media::VolumeShaper::Operation>& operation);
+ sp<media::VolumeShaper::State> getVolumeShaperState(int id);
+ sp<media::VolumeHandler> getVolumeHandler() { return mVolumeHandler; }
protected:
// for numerous
@@ -163,7 +163,7 @@
ExtendedTimestamp mSinkTimestamp;
- sp<VolumeHandler> mVolumeHandler; // handles multiple VolumeShaper configs and operations
+ sp<media::VolumeHandler> mVolumeHandler; // handles multiple VolumeShaper configs and operations
private:
// The following fields are only for fast tracks, and should be in a subclass
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 85d19cb..ef94bc3 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7638,6 +7638,10 @@
return NO_ERROR;
}
+ if (!isOutput() && !recordingAllowed(client.packageName, client.clientPid, client.clientUid)) {
+ return PERMISSION_DENIED;
+ }
+
audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
audio_io_handle_t io = mId;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 16eeccc..50c0e23 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -52,6 +52,7 @@
namespace android {
+using media::VolumeShaper;
// ----------------------------------------------------------------------------
// TrackBase
// ----------------------------------------------------------------------------
@@ -399,7 +400,7 @@
mAuxEffectId(0), mHasVolumeController(false),
mPresentationCompleteFrames(0),
mFrameMap(16 /* sink-frame-to-track-frame map memory */),
- mVolumeHandler(new VolumeHandler(sampleRate)),
+ mVolumeHandler(new media::VolumeHandler(sampleRate)),
// mSinkTimestamp
mFastIndex(-1),
mCachedVolume(1.0),
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e7c32e0..d2a2855 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1278,9 +1278,9 @@
// apply volume rules for current stream and device if necessary
checkAndSetVolume(stream,
- mVolumeCurves->getVolumeIndex(stream, device),
+ mVolumeCurves->getVolumeIndex(stream, outputDesc->device()),
outputDesc,
- device);
+ outputDesc->device());
// update the outputs if starting an output with a stream that can affect notification
// routing
@@ -4478,10 +4478,10 @@
// use device for strategy enforced audible
// 2: we are in call or the strategy phone is active on the output:
// use device for strategy phone
- // 3: the strategy for enforced audible is active but not enforced on the output:
- // use the device for strategy enforced audible
- // 4: the strategy sonification is active on the output:
+ // 3: the strategy sonification is active on the output:
// use device for strategy sonification
+ // 4: the strategy for enforced audible is active but not enforced on the output:
+ // use the device for strategy enforced audible
// 5: the strategy accessibility is active on the output:
// use device for strategy accessibility
// 6: the strategy "respectful" sonification is active on the output:
@@ -4498,10 +4498,10 @@
} else if (isInCall() ||
isStrategyActive(outputDesc, STRATEGY_PHONE)) {
device = getDeviceForStrategy(STRATEGY_PHONE, fromCache);
- } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
- device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
} else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION)) {
device = getDeviceForStrategy(STRATEGY_SONIFICATION, fromCache);
+ } else if (isStrategyActive(outputDesc, STRATEGY_ENFORCED_AUDIBLE)) {
+ device = getDeviceForStrategy(STRATEGY_ENFORCED_AUDIBLE, fromCache);
} else if (isStrategyActive(outputDesc, STRATEGY_ACCESSIBILITY)) {
device = getDeviceForStrategy(STRATEGY_ACCESSIBILITY, fromCache);
} else if (isStrategyActive(outputDesc, STRATEGY_SONIFICATION_RESPECTFUL)) {
diff --git a/services/camera/libcameraservice/common/CameraProviderManager.cpp b/services/camera/libcameraservice/common/CameraProviderManager.cpp
index 5addaf1..a02090b 100644
--- a/services/camera/libcameraservice/common/CameraProviderManager.cpp
+++ b/services/camera/libcameraservice/common/CameraProviderManager.cpp
@@ -1339,7 +1339,7 @@
desc->mReverseMapping[reverseIndex]->add(desc->mTagToNameMap.valueFor(tag), tag);
}
- descriptor = desc;
+ descriptor = std::move(desc);
return OK;
}
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index f3bb35c..2836525 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -29,12 +29,15 @@
#include <unistd.h>
#include <string.h>
+#include <pwd.h>
#include <cutils/atomic.h>
#include <cutils/properties.h> // for property_get
#include <utils/misc.h>
+#include <android/content/pm/IPackageManagerNative.h>
+
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/MemoryHeapBase.h>
@@ -80,27 +83,26 @@
namespace android {
+ using namespace android::base;
+ using namespace android::content::pm;
+
// summarized records
-// up to 48 sets, each covering an hour -- at least 2 days of coverage
+// up to 36 sets, each covering an hour -- so at least 1.5 days
// (will be longer if there are hours without any media action)
static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
-static const int kMaxRecordSets = 48;
-// individual records kept in memory
-static const int kMaxRecords = 100;
+static const int kMaxRecordSets = 36;
+// individual records kept in memory: age or count
+// age: <= 36 hours (1.5 days)
+// count: hard limit of # records
+// (0 for either of these disables that threshold)
+static const nsecs_t kMaxRecordAgeNs = 36 * 3600 * (1000*1000*1000ll);
+static const int kMaxRecords = 0;
static const char *kServiceName = "media.metrics";
-
-//using android::status_t;
-//using android::OK;
-//using android::BAD_VALUE;
-//using android::NOT_ENOUGH_DATA;
-//using android::Parcel;
-
-
void MediaAnalyticsService::instantiate() {
defaultServiceManager()->addService(
String16(kServiceName), new MediaAnalyticsService());
@@ -110,6 +112,7 @@
MediaAnalyticsService::SummarizerSet::SummarizerSet() {
mSummarizers = new List<MetricsSummarizer *>();
}
+
MediaAnalyticsService::SummarizerSet::~SummarizerSet() {
// empty the list
List<MetricsSummarizer *> *l = mSummarizers;
@@ -153,8 +156,10 @@
MediaAnalyticsService::MediaAnalyticsService()
: mMaxRecords(kMaxRecords),
+ mMaxRecordAgeNs(kMaxRecordAgeNs),
mMaxRecordSets(kMaxRecordSets),
- mNewSetInterval(kNewSetIntervalNs) {
+ mNewSetInterval(kNewSetIntervalNs),
+ mDumpProto(MediaAnalyticsItem::PROTO_V0) {
ALOGD("MediaAnalyticsService created");
// clear our queues
@@ -167,6 +172,8 @@
mItemsSubmitted = 0;
mItemsFinalized = 0;
mItemsDiscarded = 0;
+ mItemsDiscardedExpire = 0;
+ mItemsDiscardedCount = 0;
mLastSessionID = 0;
// recover any persistency we set up
@@ -177,8 +184,23 @@
ALOGD("MediaAnalyticsService destroyed");
// clean out mOpen and mFinalized
+ while (mOpen->size() > 0) {
+ MediaAnalyticsItem * oitem = *(mOpen->begin());
+ mOpen->erase(mOpen->begin());
+ delete oitem;
+ mItemsDiscarded++;
+ mItemsDiscardedCount++;
+ }
delete mOpen;
mOpen = NULL;
+
+ while (mFinalized->size() > 0) {
+ MediaAnalyticsItem * oitem = *(mFinalized->begin());
+ mFinalized->erase(mFinalized->begin());
+ delete oitem;
+ mItemsDiscarded++;
+ mItemsDiscardedCount++;
+ }
delete mFinalized;
mFinalized = NULL;
@@ -212,13 +234,15 @@
//
bool isTrusted = false;
+ ALOGV("caller has uid=%d, embedded uid=%d", uid, uid_given);
+
switch (uid) {
case AID_MEDIA:
case AID_MEDIA_CODEC:
case AID_MEDIA_EX:
case AID_MEDIA_DRM:
// trusted source, only override default values
- isTrusted = true;
+ isTrusted = true;
if (uid_given == (-1)) {
item->setUid(uid);
}
@@ -233,6 +257,9 @@
break;
}
+ item->setPkgName(getPkgName(item->getUid(), true));
+ item->setPkgVersionCode(0);
+ ALOGV("info is from uid %d pkg '%s', version %d", item->getUid(), item->getPkgName().c_str(), item->getPkgVersionCode());
mItemsSubmitted++;
@@ -316,6 +343,7 @@
return id;
}
+
status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
{
const size_t SIZE = 512;
@@ -333,22 +361,41 @@
}
// crack any parameters
- bool clear = false;
- bool summary = false;
- nsecs_t ts_since = 0;
String16 summaryOption("-summary");
+ bool summary = false;
+ String16 protoOption("-proto");
String16 clearOption("-clear");
+ bool clear = false;
String16 sinceOption("-since");
+ nsecs_t ts_since = 0;
String16 helpOption("-help");
String16 onlyOption("-only");
- const char *only = NULL;
+ AString only;
int n = args.size();
+
for (int i = 0; i < n; i++) {
String8 myarg(args[i]);
if (args[i] == clearOption) {
clear = true;
} else if (args[i] == summaryOption) {
summary = true;
+ } else if (args[i] == protoOption) {
+ i++;
+ if (i < n) {
+ String8 value(args[i]);
+ int proto = MediaAnalyticsItem::PROTO_V0; // default to original
+ char *endp;
+ const char *p = value.string();
+ proto = strtol(p, &endp, 10);
+ if (endp != p || *endp == '\0') {
+ if (proto < MediaAnalyticsItem::PROTO_FIRST) {
+ proto = MediaAnalyticsItem::PROTO_FIRST;
+ } else if (proto > MediaAnalyticsItem::PROTO_LAST) {
+ proto = MediaAnalyticsItem::PROTO_LAST;
+ }
+ mDumpProto = proto;
+ }
+ }
} else if (args[i] == sinceOption) {
i++;
if (i < n) {
@@ -368,18 +415,12 @@
i++;
if (i < n) {
String8 value(args[i]);
- const char *p = value.string();
- char *q = strdup(p);
- if (q != NULL) {
- if (only != NULL) {
- free((void*)only);
- }
- only = q;
- }
+ only = value.string();
}
} else if (args[i] == helpOption) {
result.append("Recognized parameters:\n");
result.append("-help this help message\n");
+ result.append("-proto X dump using protocol X (defaults to 1)");
result.append("-summary show summary info\n");
result.append("-clear clears out saved records\n");
result.append("-only X process records for component X\n");
@@ -398,14 +439,12 @@
dumpHeaders(result, ts_since);
- // only want 1, to avoid confusing folks that parse the output
+ // want exactly 1, to avoid confusing folks that parse the output
if (summary) {
- dumpSummaries(result, ts_since, only);
+ dumpSummaries(result, ts_since, only.c_str());
} else {
- dumpRecent(result, ts_since, only);
+ dumpRecent(result, ts_since, only.c_str());
}
- free((void*)only);
- only=NULL;
if (clear) {
@@ -430,6 +469,9 @@
const size_t SIZE = 512;
char buffer[SIZE];
+ snprintf(buffer, SIZE, "Protocol Version: %d\n", mDumpProto);
+ result.append(buffer);
+
int enabled = MediaAnalyticsItem::isEnabled();
if (enabled) {
snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
@@ -439,10 +481,14 @@
result.append(buffer);
snprintf(buffer, SIZE,
- "Since Boot: Submissions: %" PRId64
- " Finalizations: %" PRId64
- " Discarded: %" PRId64 "\n",
- mItemsSubmitted, mItemsFinalized, mItemsDiscarded);
+ "Since Boot: Submissions: %8" PRId64
+ " Finalizations: %8" PRId64 "\n",
+ mItemsSubmitted, mItemsFinalized);
+ result.append(buffer);
+ snprintf(buffer, SIZE,
+ "Records Discarded: %8" PRId64
+ " (by Count: %" PRId64 " by Expiration: %" PRId64 ")\n",
+ mItemsDiscarded, mItemsDiscardedCount, mItemsDiscardedExpire);
result.append(buffer);
snprintf(buffer, SIZE,
"Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
@@ -464,6 +510,10 @@
snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
result.append(buffer);
+ if (only != NULL && *only == '\0') {
+ only = NULL;
+ }
+
// have each of the distillers dump records
if (mSummarizerSets != NULL) {
List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
@@ -490,6 +540,10 @@
const size_t SIZE = 512;
char buffer[SIZE];
+ if (only != NULL && *only == '\0') {
+ only = NULL;
+ }
+
// show the recently recorded records
snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
result.append(buffer);
@@ -526,7 +580,7 @@
ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
continue;
}
- AString entry = (*it)->toString();
+ AString entry = (*it)->toString(mDumpProto);
result.appendFormat("%5d: %s\n", slot, entry.c_str());
slot++;
}
@@ -551,13 +605,32 @@
l->push_back(item);
}
- // keep removing old records the front until we're in-bounds
+ // keep removing old records the front until we're in-bounds (count)
if (mMaxRecords > 0) {
while (l->size() > (size_t) mMaxRecords) {
MediaAnalyticsItem * oitem = *(l->begin());
l->erase(l->begin());
delete oitem;
mItemsDiscarded++;
+ mItemsDiscardedCount++;
+ }
+ }
+
+ // keep removing old records the front until we're in-bounds (count)
+ if (mMaxRecordAgeNs > 0) {
+ nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+ while (l->size() > 0) {
+ MediaAnalyticsItem * oitem = *(l->begin());
+ nsecs_t when = oitem->getTimestamp();
+ // careful about timejumps too
+ if ((now > when) && (now-when) <= mMaxRecordAgeNs) {
+ // this (and the rest) are recent enough to keep
+ break;
+ }
+ l->erase(l->begin());
+ delete oitem;
+ mItemsDiscarded++;
+ mItemsDiscardedExpire++;
}
}
}
@@ -720,4 +793,85 @@
}
+// mapping uids to package names
+
+// give me the package name, perhaps going to find it
+AString MediaAnalyticsService::getPkgName(uid_t uid, bool addIfMissing) {
+ ssize_t i = mPkgMappings.indexOfKey(uid);
+ if (i >= 0) {
+ AString pkg = mPkgMappings.valueAt(i);
+ ALOGV("returning pkg '%s' for uid %d", pkg.c_str(), uid);
+ return pkg;
+ }
+
+ AString pkg;
+
+ if (addIfMissing == false) {
+ return pkg;
+ }
+
+ struct passwd *pw = getpwuid(uid);
+ if (pw) {
+ pkg = pw->pw_name;
+ } else {
+ pkg = "-";
+ }
+
+ // find the proper value
+
+ sp<IBinder> binder = NULL;
+ sp<IServiceManager> sm = defaultServiceManager();
+ if (sm == NULL) {
+ ALOGE("defaultServiceManager failed");
+ } else {
+ binder = sm->getService(String16("package_native"));
+ if (binder == NULL) {
+ ALOGE("getService package_native failed");
+ }
+ }
+
+ if (binder != NULL) {
+ sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+
+ std::vector<int> uids;
+ std::vector<std::string> names;
+
+ uids.push_back(uid);
+
+ binder::Status status = package_mgr->getNamesForUids(uids, &names);
+ if (!status.isOk()) {
+ ALOGE("package_native::getNamesForUids failed: %s",
+ status.exceptionMessage().c_str());
+ } else {
+ if (!names[0].empty()) {
+ pkg = names[0].c_str();
+ }
+ }
+ }
+
+ // XXX determine whether package was side-loaded or from playstore.
+ // for privacy, we only list apps loaded from playstore.
+
+ // Sanitize the package name for ":"
+ // as an example, we get "shared:android.uid.systemui"
+ // replace : with something benign (I'm going to use !)
+ if (!pkg.empty()) {
+ int n = pkg.size();
+ char *p = (char *) pkg.c_str();
+ for (int i = 0 ; i < n; i++) {
+ if (p[i] == ':') {
+ p[i] = '!';
+ }
+ }
+ }
+
+ // add it to the map, to save a subsequent lookup
+ if (!pkg.empty()) {
+ ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
+ mPkgMappings.add(uid, pkg);
+ }
+
+ return pkg;
+}
+
} // namespace android
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 6685967..4fe2fb2 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -54,6 +54,8 @@
int64_t mItemsSubmitted;
int64_t mItemsFinalized;
int64_t mItemsDiscarded;
+ int64_t mItemsDiscardedExpire;
+ int64_t mItemsDiscardedCount;
int64_t mSetsDiscarded;
MediaAnalyticsItem::SessionID_t mLastSessionID;
@@ -61,9 +63,12 @@
mutable Mutex mLock;
mutable Mutex mLock_ids;
- // the most we hold in memory
- // up to this many in each queue (open, finalized)
+ // limit how many records we'll retain
+ // by count (in each queue (open, finalized))
int32_t mMaxRecords;
+ // by time (none older than this long agan
+ nsecs_t mMaxRecordAgeNs;
+ //
// # of sets of summaries
int32_t mMaxRecordSets;
// nsecs until we start a new record set
@@ -118,6 +123,7 @@
void deleteItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *);
// support for generating output
+ int mDumpProto;
String8 dumpQueue(List<MediaAnalyticsItem*> *);
String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t, const char *only);
@@ -125,6 +131,15 @@
void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);
+ // mapping uids to package names
+ struct UidToPkgMap {
+ uid_t uid;
+ AString pkg;
+ };
+
+ KeyedVector<uid_t,AString> mPkgMappings;
+ AString getPkgName(uid_t uid, bool addIfMissing);
+
};
// ----------------------------------------------------------------------------
diff --git a/services/mediaanalytics/MetricsSummarizer.cpp b/services/mediaanalytics/MetricsSummarizer.cpp
index 3477f1f..93fe0ec 100644
--- a/services/mediaanalytics/MetricsSummarizer.cpp
+++ b/services/mediaanalytics/MetricsSummarizer.cpp
@@ -141,23 +141,23 @@
List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
for (; it != mSummaries->end(); it++) {
bool good = sameAttributes((*it), item, getIgnorables());
- ALOGV("Match against %s says %d",
- (*it)->toString().c_str(), good);
+ ALOGV("Match against %s says %d", (*it)->toString().c_str(), good);
if (good)
break;
}
if (it == mSummaries->end()) {
ALOGV("save new record");
- item = item->dup();
- if (item == NULL) {
+ MediaAnalyticsItem *nitem = item->dup();
+ if (nitem == NULL) {
ALOGE("unable to save MediaMetrics record");
}
- sortProps(item);
- item->setInt32("count",1);
- mSummaries->push_back(item);
+ sortProps(nitem);
+ nitem->setInt32("aggregated",1);
+ mergeRecord(*nitem, *item);
+ mSummaries->push_back(nitem);
} else {
ALOGV("increment existing record");
- (*it)->addInt32("count",1);
+ (*it)->addInt32("aggregated",1);
mergeRecord(*(*it), *item);
}
}
@@ -168,6 +168,71 @@
return;
}
+// keep some stats for things: sums, counts, standard deviation
+// the integer version -- all of these pieces are in 64 bits
+void MetricsSummarizer::minMaxVar64(MediaAnalyticsItem &summation, const char *key, int64_t value) {
+ if (key == NULL)
+ return;
+ int len = strlen(key) + 32;
+ char *tmpKey = (char *)malloc(len);
+
+ if (tmpKey == NULL) {
+ return;
+ }
+
+ // N - count of samples
+ snprintf(tmpKey, len, "%s.n", key);
+ summation.addInt64(tmpKey, 1);
+
+ // zero - count of samples that are zero
+ if (value == 0) {
+ snprintf(tmpKey, len, "%s.zero", key);
+ int64_t zero = 0;
+ (void) summation.getInt64(tmpKey,&zero);
+ zero++;
+ summation.setInt64(tmpKey, zero);
+ }
+
+ // min
+ snprintf(tmpKey, len, "%s.min", key);
+ int64_t min = value;
+ if (summation.getInt64(tmpKey,&min)) {
+ if (min > value) {
+ summation.setInt64(tmpKey, value);
+ }
+ } else {
+ summation.setInt64(tmpKey, value);
+ }
+
+ // max
+ snprintf(tmpKey, len, "%s.max", key);
+ int64_t max = value;
+ if (summation.getInt64(tmpKey,&max)) {
+ if (max < value) {
+ summation.setInt64(tmpKey, value);
+ }
+ } else {
+ summation.setInt64(tmpKey, value);
+ }
+
+ // components for mean, stddev;
+ // stddev = sqrt(1/4*(sumx2 - (2*sumx*sumx/n) + ((sumx/n)^2)))
+ // sum x
+ snprintf(tmpKey, len, "%s.sumX", key);
+ summation.addInt64(tmpKey, value);
+ // sum x^2
+ snprintf(tmpKey, len, "%s.sumX2", key);
+ summation.addInt64(tmpKey, value*value);
+
+
+ // last thing we do -- remove the base key from the summation
+ // record so we won't get confused about it having both individual
+ // and summary information in there.
+ summation.removeProp(key);
+
+ free(tmpKey);
+}
+
//
// Comparators
@@ -186,20 +251,23 @@
ALOGV("MetricsSummarizer::sameAttributes(): summ %s", summ->toString().c_str());
ALOGV("MetricsSummarizer::sameAttributes(): single %s", single->toString().c_str());
+ // keep different sources/users separate
+ if (single->mUid != summ->mUid) {
+ return false;
+ }
+
// this can be made better.
for(size_t i=0;i<single->mPropCount;i++) {
MediaAnalyticsItem::Prop *prop1 = &(single->mProps[i]);
const char *attrName = prop1->mName;
- ALOGV("compare on attr '%s'", attrName);
// is it something we should ignore
if (ignorable != NULL) {
const char **ig = ignorable;
- while (*ig) {
+ for (;*ig; ig++) {
if (strcmp(*ig, attrName) == 0) {
break;
}
- ig++;
}
if (*ig) {
ALOGV("we don't mind that it has attr '%s'", attrName);
@@ -218,29 +286,42 @@
}
switch (prop1->mType) {
case MediaAnalyticsItem::kTypeInt32:
- if (prop1->u.int32Value != prop2->u.int32Value)
+ if (prop1->u.int32Value != prop2->u.int32Value) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeInt64:
- if (prop1->u.int64Value != prop2->u.int64Value)
+ if (prop1->u.int64Value != prop2->u.int64Value) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeDouble:
// XXX: watch out for floating point comparisons!
- if (prop1->u.doubleValue != prop2->u.doubleValue)
+ if (prop1->u.doubleValue != prop2->u.doubleValue) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeCString:
- if (strcmp(prop1->u.CStringValue, prop2->u.CStringValue) != 0)
+ if (strcmp(prop1->u.CStringValue, prop2->u.CStringValue) != 0) {
+ ALOGV("mismatch values");
return false;
+ }
break;
case MediaAnalyticsItem::kTypeRate:
- if (prop1->u.rate.count != prop2->u.rate.count)
+ if (prop1->u.rate.count != prop2->u.rate.count) {
+ ALOGV("mismatch values");
return false;
- if (prop1->u.rate.duration != prop2->u.rate.duration)
+ }
+ if (prop1->u.rate.duration != prop2->u.rate.duration) {
+ ALOGV("mismatch values");
return false;
+ }
break;
default:
+ ALOGV("mismatch values in default type");
return false;
}
}
@@ -248,15 +329,6 @@
return true;
}
-bool MetricsSummarizer::sameAttributesId(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignorable) {
-
- // verify same user
- if (summ->mPid != single->mPid)
- return false;
-
- // and finally do the more expensive validation of the attributes
- return sameAttributes(summ, single, ignorable);
-}
int MetricsSummarizer::PropSorter(const void *a, const void *b) {
MediaAnalyticsItem::Prop *ai = (MediaAnalyticsItem::Prop *)a;
@@ -267,14 +339,8 @@
// we sort in the summaries so that it looks pretty in the dumpsys
void MetricsSummarizer::sortProps(MediaAnalyticsItem *item) {
if (item->mPropCount != 0) {
- if (DEBUG_SORT) {
- ALOGD("sortProps(pre): %s", item->toString().c_str());
- }
qsort(item->mProps, item->mPropCount,
sizeof(MediaAnalyticsItem::Prop), MetricsSummarizer::PropSorter);
- if (DEBUG_SORT) {
- ALOGD("sortProps(pst): %s", item->toString().c_str());
- }
}
}
diff --git a/services/mediaanalytics/MetricsSummarizer.h b/services/mediaanalytics/MetricsSummarizer.h
index 0b64eac..a9f0786 100644
--- a/services/mediaanalytics/MetricsSummarizer.h
+++ b/services/mediaanalytics/MetricsSummarizer.h
@@ -59,10 +59,9 @@
// various comparators
// "do these records have same attributes and values in those attrs"
- // ditto, but watch for "error" fields
bool sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);
- // attributes + from the same app/userid
- bool sameAttributesId(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);
+
+ void minMaxVar64(MediaAnalyticsItem &summ, const char *key, int64_t value);
static int PropSorter(const void *a, const void *b);
void sortProps(MediaAnalyticsItem *item);
diff --git a/services/mediaanalytics/MetricsSummarizerPlayer.cpp b/services/mediaanalytics/MetricsSummarizerPlayer.cpp
index 5162059..f882cb9 100644
--- a/services/mediaanalytics/MetricsSummarizerPlayer.cpp
+++ b/services/mediaanalytics/MetricsSummarizerPlayer.cpp
@@ -51,37 +51,43 @@
setIgnorables(player_ignorable);
}
+// NB: this is also called for the first time -- so summation == item
+// Not sure if we need a flag for that or not.
+// In this particular mergeRecord() code -- we're' ok for this.
void MetricsSummarizerPlayer::mergeRecord(MediaAnalyticsItem &summation, MediaAnalyticsItem &item) {
ALOGV("MetricsSummarizerPlayer::mergeRecord()");
- //
- // we sum time & frames.
- // be careful about our special "-1" values that indicate 'unknown'
- // treat those as 0 [basically, not summing them into the totals].
+
int64_t duration = 0;
if (item.getInt64("android.media.mediaplayer.durationMs", &duration)) {
ALOGV("found durationMs of %" PRId64, duration);
- summation.addInt64("android.media.mediaplayer.durationMs",duration);
+ minMaxVar64(summation, "android.media.mediaplayer.durationMs", duration);
}
+
int64_t playing = 0;
- if (item.getInt64("android.media.mediaplayer.playingMs", &playing))
+ if (item.getInt64("android.media.mediaplayer.playingMs", &playing)) {
ALOGV("found playingMs of %" PRId64, playing);
- if (playing >= 0) {
- summation.addInt64("android.media.mediaplayer.playingMs",playing);
- }
+ }
+ if (playing >= 0) {
+ minMaxVar64(summation,"android.media.mediaplayer.playingMs",playing);
+ }
+
int64_t frames = 0;
- if (item.getInt64("android.media.mediaplayer.frames", &frames))
+ if (item.getInt64("android.media.mediaplayer.frames", &frames)) {
ALOGV("found framess of %" PRId64, frames);
- if (frames >= 0) {
- summation.addInt64("android.media.mediaplayer.frames",frames);
- }
+ }
+ if (frames >= 0) {
+ minMaxVar64(summation,"android.media.mediaplayer.frames",frames);
+ }
+
int64_t dropped = 0;
- if (item.getInt64("android.media.mediaplayer.dropped", &dropped))
+ if (item.getInt64("android.media.mediaplayer.dropped", &dropped)) {
ALOGV("found dropped of %" PRId64, dropped);
- if (dropped >= 0) {
- summation.addInt64("android.media.mediaplayer.dropped",dropped);
- }
+ }
+ if (dropped >= 0) {
+ minMaxVar64(summation,"android.media.mediaplayer.dropped",dropped);
+ }
}
} // namespace android
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.cpp b/services/oboeservice/AAudioServiceStreamMMAP.cpp
index 43595a4..47041c5 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.cpp
+++ b/services/oboeservice/AAudioServiceStreamMMAP.cpp
@@ -92,7 +92,7 @@
aaudio_result_t result = AAudioServiceStreamBase::start();
if (!mInService && result == AAUDIO_OK) {
- startClient(mMmapClient, &mClientHandle);
+ result = startClient(mMmapClient, &mClientHandle);
}
return result;
}
@@ -107,7 +107,7 @@
aaudio_result_t result = AAudioServiceStreamBase::pause();
// TODO put before base::pause()?
if (!mInService) {
- stopClient(mClientHandle);
+ (void) stopClient(mClientHandle);
}
return result;
}
@@ -119,7 +119,7 @@
aaudio_result_t result = AAudioServiceStreamBase::stop();
// TODO put before base::stop()?
if (!mInService) {
- stopClient(mClientHandle);
+ (void) stopClient(mClientHandle);
}
return result;
}
diff --git a/services/soundtrigger/SoundTriggerHwService.cpp b/services/soundtrigger/SoundTriggerHwService.cpp
index 8891aba..952acd7 100644
--- a/services/soundtrigger/SoundTriggerHwService.cpp
+++ b/services/soundtrigger/SoundTriggerHwService.cpp
@@ -840,7 +840,7 @@
}
const bool supports_stop_all =
- (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() == ENOSYS);
+ (mHalInterface != 0) && (mHalInterface->stopAllRecognitions() != -ENOSYS);
for (size_t i = 0; i < mModels.size(); i++) {
sp<Model> model = mModels.valueAt(i);