Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9025cc09 authored by Andy Hung's avatar Andy Hung
Browse files

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
parent e9b83480
Loading
Loading
Loading
Loading
+64 −1
Original line number Diff line number Diff line
@@ -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: