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

Commit 463cb818 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Add PlaybackSettings for use with AudioTrack"

parents 7e0fea35 263b4c97
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -14995,6 +14995,7 @@ package android.media {
    method public int getPlayState();
    method public int getPlaybackHeadPosition();
    method public int getPlaybackRate();
    method public android.media.PlaybackSettings getPlaybackSettings();
    method public int getPositionNotificationPeriod();
    method public android.media.AudioDeviceInfo getPreferredOutputDevice();
    method public int getSampleRate();
@@ -15012,6 +15013,7 @@ package android.media {
    method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener);
    method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener, android.os.Handler);
    method public int setPlaybackRate(int);
    method public void setPlaybackSettings(android.media.PlaybackSettings);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredOutputDevice(android.media.AudioDeviceInfo);
    method protected deprecated void setState(int);
@@ -16375,6 +16377,24 @@ package android.media {
    method public abstract void onAudioDeviceConnection();
  }
  public final class PlaybackSettings {
    ctor public PlaybackSettings();
    method public android.media.PlaybackSettings allowDefaults();
    method public int getAudioFallbackMode();
    method public int getAudioStretchMode();
    method public float getPitch();
    method public float getSpeed();
    method public android.media.PlaybackSettings setAudioFallbackMode(int);
    method public android.media.PlaybackSettings setAudioStretchMode(int);
    method public android.media.PlaybackSettings setPitch(float);
    method public android.media.PlaybackSettings setSpeed(float);
    field public static final int AUDIO_FALLBACK_MODE_DEFAULT = 0; // 0x0
    field public static final int AUDIO_FALLBACK_MODE_FAIL = 2; // 0x2
    field public static final int AUDIO_FALLBACK_MODE_MUTE = 1; // 0x1
    field public static final int AUDIO_STRETCH_MODE_DEFAULT = 0; // 0x0
    field public static final int AUDIO_STRETCH_MODE_VOICE = 1; // 0x1
  }
  public final class Rating implements android.os.Parcelable {
    method public int describeContents();
    method public float getPercentRating();
+20 −0
Original line number Diff line number Diff line
@@ -16207,6 +16207,7 @@ package android.media {
    method public int getPlayState();
    method public int getPlaybackHeadPosition();
    method public int getPlaybackRate();
    method public android.media.PlaybackSettings getPlaybackSettings();
    method public int getPositionNotificationPeriod();
    method public android.media.AudioDeviceInfo getPreferredOutputDevice();
    method public int getSampleRate();
@@ -16224,6 +16225,7 @@ package android.media {
    method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener);
    method public void setPlaybackPositionUpdateListener(android.media.AudioTrack.OnPlaybackPositionUpdateListener, android.os.Handler);
    method public int setPlaybackRate(int);
    method public void setPlaybackSettings(android.media.PlaybackSettings);
    method public int setPositionNotificationPeriod(int);
    method public boolean setPreferredOutputDevice(android.media.AudioDeviceInfo);
    method protected deprecated void setState(int);
@@ -17590,6 +17592,24 @@ package android.media {
    method public abstract void onAudioDeviceConnection();
  }
  public final class PlaybackSettings {
    ctor public PlaybackSettings();
    method public android.media.PlaybackSettings allowDefaults();
    method public int getAudioFallbackMode();
    method public int getAudioStretchMode();
    method public float getPitch();
    method public float getSpeed();
    method public android.media.PlaybackSettings setAudioFallbackMode(int);
    method public android.media.PlaybackSettings setAudioStretchMode(int);
    method public android.media.PlaybackSettings setPitch(float);
    method public android.media.PlaybackSettings setSpeed(float);
    field public static final int AUDIO_FALLBACK_MODE_DEFAULT = 0; // 0x0
    field public static final int AUDIO_FALLBACK_MODE_FAIL = 2; // 0x2
    field public static final int AUDIO_FALLBACK_MODE_MUTE = 1; // 0x1
    field public static final int AUDIO_STRETCH_MODE_DEFAULT = 0; // 0x0
    field public static final int AUDIO_STRETCH_MODE_VOICE = 1; // 0x1
  }
  public final class Rating implements android.os.Parcelable {
    method public int describeContents();
    method public float getPercentRating();
+61 −0
Original line number Diff line number Diff line
@@ -676,6 +676,63 @@ static jint android_media_AudioTrack_get_playback_rate(JNIEnv *env, jobject thi
}


// ----------------------------------------------------------------------------
static void android_media_AudioTrack_set_playback_settings(JNIEnv *env,  jobject thiz,
        jfloatArray floatArray, jintArray intArray) {
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
            "AudioTrack not initialized");
        return;
    }

    // NOTE: Get<Primitive>ArrayRegion throws ArrayIndexOutOfBoundsException if not valid.
    // TODO: consider the actual occupancy.
    float farray[2];
    int iarray[2];
    if ((env->GetFloatArrayRegion(floatArray, 0, 2, farray), env->ExceptionCheck()) == JNI_FALSE
            &&
        (env->GetIntArrayRegion(intArray, 0, 2, iarray), env->ExceptionCheck()) == JNI_FALSE) {
        // arrays retrieved OK
        AudioPlaybackRate playbackRate;
        playbackRate.mSpeed = farray[0];
        playbackRate.mPitch = farray[1];
        playbackRate.mFallbackMode = (AudioTimestretchFallbackMode)iarray[0];
        playbackRate.mStretchMode = (AudioTimestretchStretchMode)iarray[1];
        if (lpTrack->setPlaybackRate(playbackRate) != OK) {
            jniThrowException(env, "java/lang/IllegalArgumentException",
                    "arguments out of range");
        }
    }
}


// ----------------------------------------------------------------------------
static void android_media_AudioTrack_get_playback_settings(JNIEnv *env,  jobject thiz,
        jfloatArray floatArray, jintArray intArray) {
    sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
    if (lpTrack == NULL) {
        jniThrowException(env, "java/lang/IllegalStateException",
            "AudioTrack not initialized");
        return;
    }

    AudioPlaybackRate playbackRate = lpTrack->getPlaybackRate();

    float farray[2] = {
            playbackRate.mSpeed,
            playbackRate.mPitch,
    };
    int iarray[2] = {
            playbackRate.mFallbackMode,
            playbackRate.mStretchMode,
    };
    // NOTE: Set<Primitive>ArrayRegion throws ArrayIndexOutOfBoundsException if not valid.
    env->SetFloatArrayRegion(floatArray, 0, 2, farray);
    env->SetIntArrayRegion(intArray, 0, 2, iarray);
}


// ----------------------------------------------------------------------------
static jint android_media_AudioTrack_set_marker_pos(JNIEnv *env,  jobject thiz,
        jint markerPos) {
@@ -942,6 +999,10 @@ static JNINativeMethod gMethods[] = {
                             "(I)I",     (void *)android_media_AudioTrack_set_playback_rate},
    {"native_get_playback_rate",
                             "()I",      (void *)android_media_AudioTrack_get_playback_rate},
    {"native_set_playback_settings",
                             "([F[I)V",  (void *)android_media_AudioTrack_set_playback_settings},
    {"native_get_playback_settings",
                             "([F[I)V",  (void *)android_media_AudioTrack_get_playback_settings},
    {"native_set_marker_pos","(I)I",     (void *)android_media_AudioTrack_set_marker_pos},
    {"native_get_marker_pos","()I",      (void *)android_media_AudioTrack_get_marker_pos},
    {"native_set_pos_update_period",
+64 −1
Original line number Diff line number Diff line
@@ -946,12 +946,29 @@ public class AudioTrack
    }

    /**
     * Returns the current playback rate in Hz.
     * Returns the current playback sample rate rate in Hz.
     */
    public int getPlaybackRate() {
        return native_get_playback_rate();
    }

    /**
     * Returns the current playback settings.
     * See {@link #setPlaybackSettings(PlaybackSettings)} to set playback settings
     * @return current {@link PlaybackSettings}.
     * @throws IllegalStateException if track is not initialized.
     */
    public @NonNull PlaybackSettings getPlaybackSettings() {
        float[] floatArray = new float[2];
        int[] intArray = new int[2];
        native_get_playback_settings(floatArray, intArray);
        return new PlaybackSettings()
                .setSpeed(floatArray[0])
                .setPitch(floatArray[1])
                .setAudioFallbackMode(intArray[0])
                .setAudioStretchMode(intArray[1]);
    }

    /**
     * Returns the configured audio data format. See {@link AudioFormat#ENCODING_PCM_16BIT}
     * and {@link AudioFormat#ENCODING_PCM_8BIT}.
@@ -1307,6 +1324,7 @@ public class AudioTrack
     * playback to last twice as long, but will also result in a pitch shift down by one octave.
     * The valid sample rate range is from 1 Hz to twice the value returned by
     * {@link #getNativeOutputSampleRate(int)}.
     * Use {@link #setPlaybackSettings(PlaybackSettings)} for speed control.
     * @param sampleRateInHz the sample rate expressed in Hz
     * @return error code or success, see {@link #SUCCESS}, {@link #ERROR_BAD_VALUE},
     *    {@link #ERROR_INVALID_OPERATION}
@@ -1322,6 +1340,42 @@ public class AudioTrack
    }


    /**
     * Sets the playback settings.
     * This method returns failure if it cannot apply the playback settings.
     * One possible cause is that the parameters for speed or pitch are out of range.
     * Another possible cause is that the <code>AudioTrack</code> is streaming
     * (see {@link #MODE_STREAM}) and the
     * buffer size is too small. For speeds greater than 1.0f, the <code>AudioTrack</code> buffer
     * on configuration must be larger than the speed multiplied by the minimum size
     * {@link #getMinBufferSize(int, int, int)}) to allow proper playback.
     * @param settings see {@link PlaybackSettings}. In particular,
     * speed, pitch, and audio mode should be set.
     * @throws IllegalArgumentException if the settings are invalid or not accepted.
     * @throws IllegalStateException if track is not initialized.
     */
    public void setPlaybackSettings(@NonNull PlaybackSettings settings) {
        if (settings == null) {
            throw new IllegalArgumentException("settings is null");
        }
        float[] floatArray;
        int[] intArray;
        try {
            floatArray = new float[] {
                    settings.getSpeed(),
                    settings.getPitch(),
            };
            intArray = new int[] {
                    settings.getAudioFallbackMode(),
                    settings.getAudioStretchMode(),
            };
        } catch (IllegalStateException e) {
            throw new IllegalArgumentException(e);
        }
        native_set_playback_settings(floatArray, intArray);
    }


    /**
     * Sets the position of the notification marker.  At most one marker can be active.
     * @param markerInFrames marker position in wrapping frame units similar to
@@ -2207,6 +2261,15 @@ public class AudioTrack
    private native final int native_set_playback_rate(int sampleRateInHz);
    private native final int native_get_playback_rate();

    // floatArray must be a non-null array of length >= 2
    // [0] is speed
    // [1] is pitch
    // intArray must be a non-null array of length >= 2
    // [0] is audio fallback mode
    // [1] is audio stretch mode
    private native final void native_set_playback_settings(float[] floatArray, int[] intArray);
    private native final void native_get_playback_settings(float[] floatArray, int[] intArray);

    private native final int native_set_marker_pos(int marker);
    private native final int native_get_marker_pos();

+206 −0
Original line number Diff line number Diff line
/*
 * Copyright 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.media;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import android.annotation.IntDef;

/**
 * Structure for common playback settings.
 *
 * Used by {@link AudioTrack} {@link AudioTrack#getPlaybackSettings()} and
 * {@link AudioTrack#setPlaybackSettings(PlaybackSettings)}
 * to control playback behavior.
 * <p> <strong>audio fallback mode:</strong>
 * select out-of-range parameter handling.
 * <ul>
 * <li> {@link PlaybackSettings#AUDIO_FALLBACK_MODE_DEFAULT}:
 *   System will determine best handling. </li>
 * <li> {@link PlaybackSettings#AUDIO_FALLBACK_MODE_MUTE}:
 *   Play silence for settings normally out of range.</li>
 * <li> {@link PlaybackSettings#AUDIO_FALLBACK_MODE_FAIL}:
 *   Return {@link java.lang.IllegalArgumentException} from
 *   <code>AudioTrack.setPlaybackSettings(PlaybackSettings)</code>.</li>
 * </ul>
 * <p> <strong>audio stretch mode:</strong> select
 * timestretch handling.
 * <ul>
 * <li> {@link PlaybackSettings#AUDIO_STRETCH_MODE_DEFAULT}:
 *   System will determine best selection. </li>
 * <li> {@link PlaybackSettings#AUDIO_STRETCH_MODE_VOICE}:
 *   Content is primarily voice.</li>
 * </ul>
 * <p> <strong>pitch:</strong> increases or decreases the tonal frequency of the audio content.
 * It is expressed as a multiplicative factor, where normal pitch is 1.0f.
 * <p> <strong>speed:</strong> increases or decreases the time to
 * play back a set of audio or video frames.
 * It is expressed as a multiplicative factor, where normal speed is 1.0f.
 * <p> Different combinations of speed and pitch may be used for audio playback;
 * some common ones:
 * <ul>
 * <li> <em>Pitch equals 1.0f.</em> Speed change will be done with pitch preserved,
 * often called <em>timestretching</em>.</li>
 * <li> <em>Pitch equals speed.</em> Speed change will be done by <em>resampling</em>,
 * similar to {@link AudioTrack#setPlaybackRate(int)}.</li>
 * </ul>
 */
public final class PlaybackSettings {
    /** @hide */
    @IntDef(
        value = {
                AUDIO_FALLBACK_MODE_DEFAULT,
                AUDIO_FALLBACK_MODE_MUTE,
                AUDIO_FALLBACK_MODE_FAIL,
        }
    )
    @Retention(RetentionPolicy.SOURCE)
    public @interface AudioFallbackMode {}
    public static final int AUDIO_FALLBACK_MODE_DEFAULT = 0;
    public static final int AUDIO_FALLBACK_MODE_MUTE = 1;
    public static final int AUDIO_FALLBACK_MODE_FAIL = 2;

    /** @hide */
    @IntDef(
        value = {
                AUDIO_STRETCH_MODE_DEFAULT,
                AUDIO_STRETCH_MODE_VOICE,
        }
    )
    @Retention(RetentionPolicy.SOURCE)
    public @interface AudioStretchMode {}
    public static final int AUDIO_STRETCH_MODE_DEFAULT = 0;
    public static final int AUDIO_STRETCH_MODE_VOICE = 1;

    // flags to indicate which settings are actually set
    private static final int SET_SPEED               = 1 << 0;
    private static final int SET_PITCH               = 1 << 1;
    private static final int SET_AUDIO_FALLBACK_MODE = 1 << 2;
    private static final int SET_AUDIO_STRETCH_MODE  = 1 << 3;
    private int mSet = 0;

    // settings
    private int mAudioFallbackMode = AUDIO_FALLBACK_MODE_DEFAULT;
    private int mAudioStretchMode = AUDIO_STRETCH_MODE_DEFAULT;
    private float mPitch = 1.0f;
    private float mSpeed = 1.0f;

    /**
     * Allows defaults to be returned for properties not set.
     * Otherwise a {@link java.lang.IllegalArgumentException} exception
     * is raised when getting those properties
     * which have defaults but have never been set.
     * @return this <code>PlaybackSettings</code> instance.
     */
    public PlaybackSettings allowDefaults() {
        mSet |= SET_AUDIO_FALLBACK_MODE | SET_AUDIO_STRETCH_MODE | SET_PITCH | SET_SPEED;
        return this;
    }

    /**
     * Sets the audio fallback mode.
     * @param audioFallbackMode
     * @return this <code>PlaybackSettings</code> instance.
     */
    public PlaybackSettings setAudioFallbackMode(@AudioFallbackMode int audioFallbackMode) {
        mAudioFallbackMode = audioFallbackMode;
        mSet |= SET_AUDIO_FALLBACK_MODE;
        return this;
    }

    /**
     * Retrieves the audio fallback mode.
     * @return audio fallback mode
     * @throws IllegalStateException if the audio fallback mode is not set.
     */
    public @AudioFallbackMode int getAudioFallbackMode() {
        if ((mSet & SET_AUDIO_FALLBACK_MODE) == 0) {
            throw new IllegalStateException("audio fallback mode not set");
        }
        return mAudioFallbackMode;
    }

    /**
     * Sets the audio stretch mode.
     * @param audioStretchMode
     * @return this <code>PlaybackSettings</code> instance.
     */
    public PlaybackSettings setAudioStretchMode(@AudioStretchMode int audioStretchMode) {
        mAudioStretchMode = audioStretchMode;
        mSet |= SET_AUDIO_STRETCH_MODE;
        return this;
    }

    /**
     * Retrieves the audio stretch mode.
     * @return audio stretch mode
     * @throws IllegalStateException if the audio stretch mode is not set.
     */
    public @AudioStretchMode int getAudioStretchMode() {
        if ((mSet & SET_AUDIO_STRETCH_MODE) == 0) {
            throw new IllegalStateException("audio stretch mode not set");
        }
        return mAudioStretchMode;
    }

    /**
     * Sets the pitch factor.
     * @param pitch
     * @return this <code>PlaybackSettings</code> instance.
     */
    public PlaybackSettings setPitch(float pitch) {
        mPitch = pitch;
        mSet |= SET_PITCH;
        return this;
    }

    /**
     * Retrieves the pitch factor.
     * @return pitch
     * @throws IllegalStateException if pitch is not set.
     */
    public float getPitch() {
        if ((mSet & SET_PITCH) == 0) {
            throw new IllegalStateException("pitch not set");
        }
        return mPitch;
    }

    /**
     * Sets the speed factor.
     * @param speed
     * @return this <code>PlaybackSettings</code> instance.
     */
    public PlaybackSettings setSpeed(float speed) {
        mSpeed = speed;
        mSet |= SET_SPEED;
        return this;
    }

    /**
     * Retrieves the speed factor.
     * @return speed
     * @throws IllegalStateException if speed is not set.
     */
    public float getSpeed() {
        if ((mSet & SET_SPEED) == 0) {
            throw new IllegalStateException("speed not set");
        }
        return mSpeed;
    }
}