diff options
| author | 2017-01-31 19:27:04 -0800 | |
|---|---|---|
| committer | 2017-02-03 09:18:34 -0800 | |
| commit | 9025cc090bf9fcb78f4417a63e24e41c8ea41dc0 (patch) | |
| tree | 8a3236c9b058f9516aaabbe2e753fd42115d0530 | |
| parent | e9b8348027074996b08796816e0ce0998169a881 (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.java | 65 |
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: |