summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Andy Hung <hunga@google.com> 2017-01-31 19:27:04 -0800
committer Andy Hung <hunga@google.com> 2017-02-03 09:18:34 -0800
commit9025cc090bf9fcb78f4417a63e24e41c8ea41dc0 (patch)
tree8a3236c9b058f9516aaabbe2e753fd42115d0530
parente9b8348027074996b08796816e0ce0998169a881 (diff)
AudioTrack: Enable deep buffer under certain conditions
Under certain conditions, i.e. USAGE_MEDIA and CONTENT_TYPE UNKNOWN, MUSIC, MOVIE and large buffers we route the AudioTrack to deep buffer to save power. Change-Id: Ibc8a31750999da842e36156f939448989ee50511 Test: Play Movies, CTS Bug: 30687201
-rw-r--r--media/java/android/media/AudioTrack.java65
1 files changed, 64 insertions, 1 deletions
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index b23f5fd68340..89fefcead347 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -27,6 +27,7 @@ import java.util.Collection;
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityThread;
import android.content.Context;
import android.os.Handler;
@@ -538,6 +539,15 @@ public class AudioTrack extends PlayerBase
throw new IllegalArgumentException("Illegal null AudioFormat");
}
+ // Check if we should enable deep buffer mode
+ if (shouldEnablePowerSaving(mAttributes, format, bufferSizeInBytes, mode)) {
+ mAttributes = new AudioAttributes.Builder(mAttributes)
+ .replaceFlags((mAttributes.getAllFlags()
+ | AudioAttributes.FLAG_DEEP_BUFFER)
+ & ~AudioAttributes.FLAG_LOW_LATENCY)
+ .build();
+ }
+
// remember which looper is associated with the AudioTrack instantiation
Looper looper;
if ((looper = Looper.myLooper()) == null) {
@@ -861,7 +871,10 @@ public class AudioTrack extends PlayerBase
.build();
break;
case PERFORMANCE_MODE_NONE:
- break;
+ if (!shouldEnablePowerSaving(mAttributes, mFormat, mBufferSizeInBytes, mMode)) {
+ break; // do not enable deep buffer mode.
+ }
+ // permitted to fall through to enable deep buffer
case PERFORMANCE_MODE_POWER_SAVING:
mAttributes = new AudioAttributes.Builder(mAttributes)
.replaceFlags((mAttributes.getAllFlags()
@@ -912,6 +925,56 @@ public class AudioTrack extends PlayerBase
AudioFormat.CHANNEL_OUT_SIDE_LEFT |
AudioFormat.CHANNEL_OUT_SIDE_RIGHT;
+ // Returns a boolean whether the attributes, format, bufferSizeInBytes, mode allow
+ // power saving to be automatically enabled for an AudioTrack. Returns false if
+ // power saving is already enabled in the attributes parameter.
+ private static boolean shouldEnablePowerSaving(
+ @Nullable AudioAttributes attributes, @Nullable AudioFormat format,
+ int bufferSizeInBytes, int mode) {
+ // If no attributes, OK
+ // otherwise check attributes for USAGE_MEDIA and CONTENT_UNKNOWN, MUSIC, or MOVIE.
+ if (attributes != null &&
+ (attributes.getAllFlags() != 0 // cannot have any special flags
+ || attributes.getUsage() != AudioAttributes.USAGE_MEDIA
+ || (attributes.getContentType() != AudioAttributes.CONTENT_TYPE_UNKNOWN
+ && attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MUSIC
+ && attributes.getContentType() != AudioAttributes.CONTENT_TYPE_MOVIE))) {
+ return false;
+ }
+
+ // Format must be fully specified and be linear pcm
+ if (format == null
+ || format.getSampleRate() == AudioFormat.SAMPLE_RATE_UNSPECIFIED
+ || !AudioFormat.isEncodingLinearPcm(format.getEncoding())
+ || !AudioFormat.isValidEncoding(format.getEncoding())
+ || format.getChannelCount() < 1) {
+ return false;
+ }
+
+ // Mode must be streaming
+ if (mode != MODE_STREAM) {
+ return false;
+ }
+
+ // A buffer size of 0 is always compatible with deep buffer (when called from the Builder)
+ // but for app compatibility we only use deep buffer power saving for large buffer sizes.
+ if (bufferSizeInBytes != 0) {
+ final long BUFFER_TARGET_MODE_STREAM_MS = 100;
+ final int MILLIS_PER_SECOND = 1000;
+ final long bufferTargetSize =
+ BUFFER_TARGET_MODE_STREAM_MS
+ * format.getChannelCount()
+ * format.getBytesPerSample(format.getEncoding())
+ * format.getSampleRate()
+ / MILLIS_PER_SECOND;
+ if (bufferSizeInBytes < bufferTargetSize) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
// Convenience method for the constructor's parameter checks.
// This is where constructor IllegalArgumentException-s are thrown
// postconditions: