media: use PlaybackSettings in MediaSync and MediaPlayer
Bug: 19666434
Change-Id: Ic5e517534a26f4e3b0294205e0b93f95338bf072
diff --git a/api/current.txt b/api/current.txt
index e509a00..8a4d0b6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -15988,6 +15988,7 @@
method public int getAudioSessionId();
method public int getCurrentPosition();
method public int getDuration();
+ method public android.media.PlaybackSettings getPlaybackSettings();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.MediaPlayer.TrackInfo[] getTrackInfo() throws java.lang.IllegalStateException;
method public int getVideoHeight();
@@ -16024,6 +16025,7 @@
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackRate(float, int);
+ method public void setPlaybackSettings(android.media.PlaybackSettings);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setVideoScalingMode(int);
@@ -16049,7 +16051,9 @@
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
- field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; // 0x0
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; // 0x2
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
@@ -16342,12 +16346,16 @@
method public void configureAudioTrack(android.media.AudioTrack);
method public void configureSurface(android.view.Surface);
method public final android.view.Surface createInputSurface();
+ method public android.media.PlaybackSettings getPlaybackSettings();
method public boolean getTimestamp(android.media.MediaTimestamp);
method public void queueAudio(java.nio.ByteBuffer, int, int, long);
method public final void release();
method public void setCallback(android.media.MediaSync.Callback, android.os.Handler);
method public void setPlaybackRate(float, int);
- field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
+ method public void setPlaybackSettings(android.media.PlaybackSettings);
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; // 0x0
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; // 0x2
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; // 0x1
}
public static abstract class MediaSync.Callback {
diff --git a/api/system-current.txt b/api/system-current.txt
index 8b4052b..14e9563 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -17201,6 +17201,7 @@
method public int getAudioSessionId();
method public int getCurrentPosition();
method public int getDuration();
+ method public android.media.PlaybackSettings getPlaybackSettings();
method public int getSelectedTrack(int) throws java.lang.IllegalStateException;
method public android.media.MediaPlayer.TrackInfo[] getTrackInfo() throws java.lang.IllegalStateException;
method public int getVideoHeight();
@@ -17237,6 +17238,7 @@
method public void setOnTimedTextListener(android.media.MediaPlayer.OnTimedTextListener);
method public void setOnVideoSizeChangedListener(android.media.MediaPlayer.OnVideoSizeChangedListener);
method public void setPlaybackRate(float, int);
+ method public void setPlaybackSettings(android.media.PlaybackSettings);
method public void setScreenOnWhilePlaying(boolean);
method public void setSurface(android.view.Surface);
method public void setVideoScalingMode(int);
@@ -17262,7 +17264,9 @@
field public static final int MEDIA_INFO_VIDEO_RENDERING_START = 3; // 0x3
field public static final int MEDIA_INFO_VIDEO_TRACK_LAGGING = 700; // 0x2bc
field public static final java.lang.String MEDIA_MIMETYPE_TEXT_SUBRIP = "application/x-subrip";
- field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; // 0x0
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; // 0x2
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT = 1; // 0x1
field public static final int VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING = 2; // 0x2
}
@@ -17557,12 +17561,16 @@
method public void configureAudioTrack(android.media.AudioTrack);
method public void configureSurface(android.view.Surface);
method public final android.view.Surface createInputSurface();
+ method public android.media.PlaybackSettings getPlaybackSettings();
method public boolean getTimestamp(android.media.MediaTimestamp);
method public void queueAudio(java.nio.ByteBuffer, int, int, long);
method public final void release();
method public void setCallback(android.media.MediaSync.Callback, android.os.Handler);
method public void setPlaybackRate(float, int);
- field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0; // 0x0
+ method public void setPlaybackSettings(android.media.PlaybackSettings);
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; // 0x0
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; // 0x2
+ field public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; // 0x1
}
public static abstract class MediaSync.Callback {
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 210d08f..85c6c67 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -17,6 +17,7 @@
package android.media;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.content.ContentResolver;
@@ -44,6 +45,7 @@
import android.media.AudioManager;
import android.media.MediaFormat;
import android.media.MediaTimeProvider;
+import android.media.PlaybackSettings;
import android.media.SubtitleController;
import android.media.SubtitleController.Anchor;
import android.media.SubtitleData;
@@ -471,16 +473,21 @@
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
- * <tr><td>setScreenOnWhilePlaying</></td>
- * <td>any </p></td>
- * <td>{} </p></td>
- * <td>This method can be called in any state and calling it does not change
- * the object state. </p></td></tr>
* <tr><td>setPlaybackRate</p></td>
* <td>any </p></td>
* <td>{} </p></td>
* <td>This method can be called in any state and calling it does not change
* the object state. </p></td></tr>
+ * <tr><td>setPlaybackSettings</p></td>
+ * <td>any </p></td>
+ * <td>{} </p></td>
+ * <td>This method can be called in any state and calling it does not change
+ * the object state. </p></td></tr>
+ * <tr><td>setScreenOnWhilePlaying</></td>
+ * <td>any </p></td>
+ * <td>{} </p></td>
+ * <td>This method can be called in any state and calling it does not change
+ * the object state. </p></td></tr>
* <tr><td>setVolume </p></td>
* <td>{Idle, Initialized, Stopped, Prepared, Started, Paused,
* PlaybackCompleted}</p></td>
@@ -1342,6 +1349,8 @@
public native boolean isPlaying();
/**
+ * Change playback speed of audio by resampling the audio.
+ * <p>
* Specifies resampling as audio mode for variable rate playback, i.e.,
* resample the waveform based on the requested playback rate to get
* a new waveform, and play back the new waveform at the original sampling
@@ -1349,33 +1358,44 @@
* When rate is larger than 1.0, pitch becomes higher.
* When rate is smaller than 1.0, pitch becomes lower.
*/
- public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0;
+ public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2;
/**
+ * Change playback speed of audio without changing its pitch.
+ * <p>
* Specifies time stretching as audio mode for variable rate playback.
* Time stretching changes the duration of the audio samples without
* affecting its pitch.
- * FIXME: implement time strectching.
- * @hide
+ * <p>
+ * This mode is only supported for a limited range of playback speed factors,
+ * e.g. between 1/2x and 2x.
*/
public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1;
+ /**
+ * Change playback speed of audio without changing its pitch, and
+ * possibly mute audio if time stretching is not supported for the playback
+ * speed.
+ * <p>
+ * Try to keep audio pitch when changing the playback rate, but allow the
+ * system to determine how to change audio playback if the rate is out
+ * of range.
+ */
+ public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0;
+
/** @hide */
@IntDef(
value = {
+ PLAYBACK_RATE_AUDIO_MODE_DEFAULT,
+ PLAYBACK_RATE_AUDIO_MODE_STRETCH,
PLAYBACK_RATE_AUDIO_MODE_RESAMPLE,
- PLAYBACK_RATE_AUDIO_MODE_STRETCH })
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface PlaybackRateAudioMode {}
/**
* Sets playback rate and audio mode.
*
- * <p> The supported audio modes are:
- * <ul>
- * <li> {@link #PLAYBACK_RATE_AUDIO_MODE_RESAMPLE}
- * </ul>
- *
* @param rate the ratio between desired playback rate and normal one.
* @param audioMode audio playback mode. Must be one of the supported
* audio modes.
@@ -1385,14 +1405,46 @@
* @throws IllegalArgumentException if audioMode is not supported.
*/
public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) {
- if (!isAudioPlaybackModeSupported(audioMode)) {
+ PlaybackSettings settings = new PlaybackSettings();
+ settings.allowDefaults();
+ switch (audioMode) {
+ case PLAYBACK_RATE_AUDIO_MODE_DEFAULT:
+ settings.setSpeed(rate).setPitch(1.0f);
+ break;
+ case PLAYBACK_RATE_AUDIO_MODE_STRETCH:
+ settings.setSpeed(rate).setPitch(1.0f)
+ .setAudioFallbackMode(settings.AUDIO_FALLBACK_MODE_FAIL);
+ break;
+ case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE:
+ settings.setSpeed(rate).setPitch(rate);
+ break;
+ default:
final String msg = "Audio playback mode " + audioMode + " is not supported";
throw new IllegalArgumentException(msg);
}
- _setPlaybackRate(rate);
+ setPlaybackSettings(settings);
}
- private native void _setPlaybackRate(float rate) throws IllegalStateException;
+ /**
+ * Sets playback rate using {@link PlaybackSettings}.
+ *
+ * @param settings the playback settings.
+ *
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized.
+ * @throws IllegalArgumentException if settings is not supported.
+ */
+ public native void setPlaybackSettings(@NonNull PlaybackSettings settings);
+
+ /**
+ * Gets the playback settings, containing the current playback rate.
+ *
+ * @return the playback settings.
+ * @throws IllegalStateException if the internal player engine has not been
+ * initialized.
+ */
+ @NonNull
+ public native PlaybackSettings getPlaybackSettings();
/**
* Seeks to specified time position.
@@ -3219,14 +3271,6 @@
mode == VIDEO_SCALING_MODE_SCALE_TO_FIT_WITH_CROPPING);
}
- /*
- * Test whether a given audio playback mode is supported.
- * TODO query supported AudioPlaybackMode from player.
- */
- private boolean isAudioPlaybackModeSupported(int mode) {
- return (mode == PLAYBACK_RATE_AUDIO_MODE_RESAMPLE);
- }
-
/** @hide */
static class TimeProvider implements MediaPlayer.OnSeekCompleteListener,
MediaTimeProvider {
diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java
index 74a2fb2..cc894cb 100644
--- a/media/java/android/media/MediaSync.java
+++ b/media/java/android/media/MediaSync.java
@@ -20,6 +20,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.media.AudioTrack;
+import android.media.PlaybackSettings;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -282,60 +283,58 @@
public native final Surface createInputSurface();
/**
- * Specifies resampling as audio mode for variable rate playback, i.e.,
- * resample the waveform based on the requested playback rate to get
+ * Resample audio data when changing playback speed.
+ * <p>
+ * Resample the waveform based on the requested playback rate to get
* a new waveform, and play back the new waveform at the original sampling
* frequency.
- * When rate is larger than 1.0, pitch becomes higher.
- * When rate is smaller than 1.0, pitch becomes lower.
+ * <p><ul>
+ * <li>When rate is larger than 1.0, pitch becomes higher.
+ * <li>When rate is smaller than 1.0, pitch becomes lower.
+ * </ul>
*/
- public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 0;
+ public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2;
/**
- * Specifies time stretching as audio mode for variable rate playback.
+ * Time stretch audio when changing playback speed.
+ * <p>
* Time stretching changes the duration of the audio samples without
- * affecting its pitch.
- * FIXME: implement time strectching.
- * @hide
+ * affecting their pitch. This is only supported for a limited range
+ * of playback speeds, e.g. from 1/2x to 2x. If the rate is adjusted
+ * beyond this limit, the rate change will fail.
*/
public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1;
+ /**
+ * Time stretch audio when changing playback speed, and may mute if
+ * stretching is no longer supported.
+ * <p>
+ * Time stretching changes the duration of the audio samples without
+ * affecting their pitch. This is only supported for a limited range
+ * of playback speeds, e.g. from 1/2x to 2x. When it is no longer
+ * supported, the audio may be muted. Using this mode will not fail
+ * for non-negative playback rates.
+ */
+ public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0;
+
/** @hide */
@IntDef(
value = {
+ PLAYBACK_RATE_AUDIO_MODE_DEFAULT,
+ PLAYBACK_RATE_AUDIO_MODE_STRETCH,
PLAYBACK_RATE_AUDIO_MODE_RESAMPLE,
- PLAYBACK_RATE_AUDIO_MODE_STRETCH })
+ })
@Retention(RetentionPolicy.SOURCE)
public @interface PlaybackRateAudioMode {}
/**
- * Sets playback rate. It does same as {@link #setPlaybackRate(float, int)},
- * except that it always uses {@link #PLAYBACK_RATE_AUDIO_MODE_STRETCH} for audioMode.
- *
- * @param rate the ratio between desired playback rate and normal one. 1.0 means normal
- * playback speed. 0.0 means stop or pause. Value larger than 1.0 means faster playback,
- * while value between 0.0 and 1.0 for slower playback.
- *
- * @throws IllegalStateException if the internal sync engine or the audio track has not
- * been initialized.
- * TODO: unhide when PLAYBACK_RATE_AUDIO_MODE_STRETCH is supported.
- * @hide
- */
- public void setPlaybackRate(float rate) {
- setPlaybackRate(rate, PLAYBACK_RATE_AUDIO_MODE_STRETCH);
- }
-
- /**
* Sets playback rate and audio mode.
*
- * <p> The supported audio modes are:
- * <ul>
- * <li> {@link #PLAYBACK_RATE_AUDIO_MODE_RESAMPLE}
- * </ul>
- *
* @param rate the ratio between desired playback rate and normal one. 1.0 means normal
- * playback speed. 0.0 means stop or pause. Value larger than 1.0 means faster playback,
- * while value between 0.0 and 1.0 for slower playback.
+ * playback speed. 0.0 means pause. Value larger than 1.0 means faster playback,
+ * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate
+ * does not change as a result of this call. To restore the original rate at any time,
+ * use 1.0.
* @param audioMode audio playback mode. Must be one of the supported
* audio modes.
*
@@ -344,52 +343,104 @@
* @throws IllegalArgumentException if audioMode is not supported.
*/
public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) {
- if (!isAudioPlaybackModeSupported(audioMode)) {
- final String msg = "Audio playback mode " + audioMode + " is not supported";
- throw new IllegalArgumentException(msg);
- }
-
- int status = AudioTrack.SUCCESS;
- if (mAudioTrack != null) {
- int nativeSampleRateInHz = mAudioTrack.getSampleRate();
- int playbackSampleRate = (int)(rate * nativeSampleRateInHz + 0.5);
- rate = playbackSampleRate / (float)nativeSampleRateInHz;
-
- try {
- if (rate == 0.0) {
- mAudioTrack.pause();
- } else {
- status = mAudioTrack.setPlaybackRate(playbackSampleRate);
- mAudioTrack.play();
- }
- } catch (IllegalStateException e) {
- throw e;
+ PlaybackSettings rateSettings = new PlaybackSettings();
+ rateSettings.allowDefaults();
+ switch (audioMode) {
+ case PLAYBACK_RATE_AUDIO_MODE_DEFAULT:
+ rateSettings.setSpeed(rate).setPitch(1.0f);
+ break;
+ case PLAYBACK_RATE_AUDIO_MODE_STRETCH:
+ rateSettings.setSpeed(rate).setPitch(1.0f)
+ .setAudioFallbackMode(rateSettings.AUDIO_FALLBACK_MODE_FAIL);
+ break;
+ case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE:
+ rateSettings.setSpeed(rate).setPitch(rate);
+ break;
+ default:
+ {
+ final String msg = "Audio playback mode " + audioMode + " is not supported";
+ throw new IllegalArgumentException(msg);
}
}
+ setPlaybackSettings(rateSettings);
+ }
- if (status != AudioTrack.SUCCESS) {
- throw new IllegalArgumentException("Fail to set playback rate in audio track");
- }
+ /**
+ * Sets playback rate using {@link PlaybackSettings}.
+ * <p>
+ * When using MediaSync with {@link AudioTrack}, set playback settings using this
+ * call instead of calling it directly on the track, so that the sync is aware of
+ * the settings change.
+ * <p>
+ * This call also works if there is no audio track.
+ *
+ * @param settings the playback settings to use. {@link PlaybackSettings#getSpeed
+ * Speed} is the ratio between desired playback rate and normal one. 1.0 means
+ * normal playback speed. 0.0 means pause. Value larger than 1.0 means faster playback,
+ * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate
+ * does not change as a result of this call. To restore the original rate at any time,
+ * use speed of 1.0.
+ *
+ * @throws IllegalStateException if the internal sync engine or the audio track has not
+ * been initialized.
+ * @throws IllegalArgumentException if the settings are not supported.
+ */
+ public void setPlaybackSettings(@NonNull PlaybackSettings settings) {
+ float rate;
+ try {
+ rate = settings.getSpeed();
- synchronized(mAudioLock) {
- mPlaybackRate = rate;
+ // rate is specified
+ if (mAudioTrack != null) {
+ try {
+ if (rate == 0.0) {
+ mAudioTrack.pause();
+ } else {
+ mAudioTrack.setPlaybackSettings(settings);
+ mAudioTrack.play();
+ }
+ } catch (IllegalStateException e) {
+ throw e;
+ }
+ }
+
+ synchronized(mAudioLock) {
+ mPlaybackRate = rate;
+ }
+ if (mPlaybackRate != 0.0 && mAudioThread != null) {
+ postRenderAudio(0);
+ }
+ native_setPlaybackRate(mPlaybackRate);
+ } catch (IllegalStateException e) {
+ // rate is not specified; still, propagate settings to audio track
+ if (mAudioTrack != null) {
+ mAudioTrack.setPlaybackSettings(settings);
+ }
}
- if (mPlaybackRate != 0.0 && mAudioThread != null) {
- postRenderAudio(0);
+ }
+
+ /**
+ * Gets the playback rate using {@link PlaybackSettings}.
+ *
+ * @return the playback rate being used.
+ *
+ * @throws IllegalStateException if the internal sync engine or the audio track has not
+ * been initialized.
+ */
+ @NonNull
+ public PlaybackSettings getPlaybackSettings() {
+ if (mAudioTrack != null) {
+ return mAudioTrack.getPlaybackSettings();
+ } else {
+ PlaybackSettings settings = new PlaybackSettings();
+ settings.allowDefaults();
+ settings.setSpeed(mPlaybackRate);
+ return settings;
}
- native_setPlaybackRate(mPlaybackRate);
}
private native final void native_setPlaybackRate(float rate);
- /*
- * Test whether a given audio playback mode is supported.
- * TODO query supported AudioPlaybackMode from audio track.
- */
- private boolean isAudioPlaybackModeSupported(int mode) {
- return (mode == PLAYBACK_RATE_AUDIO_MODE_RESAMPLE);
- }
-
/**
* Get current playback position.
* <p>
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index c247220..b79a6bb 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -20,6 +20,7 @@
#include "utils/Log.h"
#include <media/mediaplayer.h>
+#include <media/AudioResamplerPublic.h>
#include <media/IMediaHTTPService.h>
#include <media/MediaPlayerInterface.h>
#include <stdio.h>
@@ -37,6 +38,7 @@
#include "utils/KeyedVector.h"
#include "utils/String8.h"
#include "android_media_MediaDataSource.h"
+#include "android_media_PlaybackSettings.h"
#include "android_media_Utils.h"
#include "android_os_Parcel.h"
@@ -66,6 +68,8 @@
};
static fields_t fields;
+static PlaybackSettings::fields_t gPlaybackSettingsFields;
+
static Mutex sLock;
// ----------------------------------------------------------------------------
@@ -420,15 +424,55 @@
}
static void
-android_media_MediaPlayer_setPlaybackRate(JNIEnv *env, jobject thiz, jfloat rate)
+android_media_MediaPlayer_setPlaybackSettings(JNIEnv *env, jobject thiz, jobject settings)
{
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
- ALOGV("setPlaybackRate: %f", rate);
- process_media_player_call(env, thiz, mp->setPlaybackRate(rate), NULL, NULL);
+
+ PlaybackSettings pbs;
+ pbs.fillFromJobject(env, gPlaybackSettingsFields, settings);
+ ALOGV("setPlaybackSettings: %d:%f %d:%f %d:%u %d:%u",
+ pbs.speedSet, pbs.audioRate.mSpeed,
+ pbs.pitchSet, pbs.audioRate.mPitch,
+ pbs.audioFallbackModeSet, pbs.audioRate.mFallbackMode,
+ pbs.audioStretchModeSet, pbs.audioRate.mStretchMode);
+
+ // TODO: pass playback settings to mediaplayer when audiotrack supports it
+ process_media_player_call(env, thiz, mp->setPlaybackRate(pbs.audioRate.mSpeed), NULL, NULL);
+}
+
+static jobject
+android_media_MediaPlayer_getPlaybackSettings(JNIEnv *env, jobject thiz)
+{
+ sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
+ if (mp == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ PlaybackSettings pbs;
+ AudioPlaybackRate &audioRate = pbs.audioRate;
+
+ audioRate.mSpeed = 1.0f;
+ audioRate.mPitch = 1.0f;
+ audioRate.mFallbackMode = AUDIO_TIMESTRETCH_FALLBACK_DEFAULT;
+ audioRate.mStretchMode = AUDIO_TIMESTRETCH_STRETCH_DEFAULT;
+
+ // TODO: get this from mediaplayer when audiotrack supports it
+ // process_media_player_call(
+ // env, thiz, mp->getPlaybackSettings(&audioRate), NULL, NULL);
+ ALOGV("getPlaybackSettings: %f %f %d %d",
+ audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
+
+ pbs.speedSet = true;
+ pbs.pitchSet = true;
+ pbs.audioFallbackModeSet = true;
+ pbs.audioStretchModeSet = true;
+
+ return pbs.asJobject(env, gPlaybackSettingsFields);
}
static void
@@ -697,6 +741,8 @@
return;
}
+ env->DeleteLocalRef(clazz);
+
clazz = env->FindClass("android/net/ProxyInfo");
if (clazz == NULL) {
return;
@@ -710,6 +756,10 @@
fields.proxyConfigGetExclusionList =
env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
+
+ env->DeleteLocalRef(clazz);
+
+ gPlaybackSettingsFields.init(env);
}
static void
@@ -898,7 +948,8 @@
{"_stop", "()V", (void *)android_media_MediaPlayer_stop},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
- {"_setPlaybackRate", "(F)V", (void *)android_media_MediaPlayer_setPlaybackRate},
+ {"setPlaybackSettings", "(Landroid/media/PlaybackSettings;)V", (void *)android_media_MediaPlayer_setPlaybackSettings},
+ {"getPlaybackSettings", "()Landroid/media/PlaybackSettings;", (void *)android_media_MediaPlayer_getPlaybackSettings},
{"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
{"_pause", "()V", (void *)android_media_MediaPlayer_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
diff --git a/media/jni/android_media_PlaybackSettings.h b/media/jni/android_media_PlaybackSettings.h
new file mode 100644
index 0000000..1f4f256
--- /dev/null
+++ b/media/jni/android_media_PlaybackSettings.h
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+#ifndef _ANDROID_MEDIA_PLAYBACK_SETTINGS_H_
+#define _ANDROID_MEDIA_PLAYBACK_SETTINGS_H_
+
+#include <media/AudioResamplerPublic.h>
+
+namespace android {
+
+// This entire class is inline as it is used from both core and media
+struct PlaybackSettings {
+ AudioPlaybackRate audioRate;
+ bool speedSet;
+ bool pitchSet;
+ bool audioFallbackModeSet;
+ bool audioStretchModeSet;
+
+ struct fields_t {
+ jclass clazz;
+ jmethodID constructID;
+
+ jfieldID speed;
+ jfieldID pitch;
+ jfieldID audio_fallback_mode;
+ jfieldID audio_stretch_mode;
+ jfieldID set;
+ jint set_speed;
+ jint set_pitch;
+ jint set_audio_fallback_mode;
+ jint set_audio_stretch_mode;
+
+ void init(JNIEnv *env) {
+ jclass lclazz = env->FindClass("android/media/PlaybackSettings");
+ if (lclazz == NULL) {
+ return;
+ }
+
+ clazz = (jclass)env->NewGlobalRef(lclazz);
+ if (clazz == NULL) {
+ return;
+ }
+
+ constructID = env->GetMethodID(clazz, "<init>", "()V");
+
+ speed = env->GetFieldID(clazz, "mSpeed", "F");
+ pitch = env->GetFieldID(clazz, "mPitch", "F");
+ audio_fallback_mode = env->GetFieldID(clazz, "mAudioFallbackMode", "I");
+ audio_stretch_mode = env->GetFieldID(clazz, "mAudioStretchMode", "I");
+ set = env->GetFieldID(clazz, "mSet", "I");
+
+ set_speed =
+ env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "SET_SPEED", "I"));
+ set_pitch =
+ env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "SET_PITCH", "I"));
+ set_audio_fallback_mode = env->GetStaticIntField(
+ clazz, env->GetStaticFieldID(clazz, "SET_AUDIO_FALLBACK_MODE", "I"));
+ set_audio_stretch_mode = env->GetStaticIntField(
+ clazz, env->GetStaticFieldID(clazz, "SET_AUDIO_STRETCH_MODE", "I"));
+
+ env->DeleteLocalRef(lclazz);
+ }
+
+ void exit(JNIEnv *env) {
+ env->DeleteGlobalRef(clazz);
+ clazz = NULL;
+ }
+ };
+
+ void fillFromJobject(JNIEnv *env, const fields_t& fields, jobject settings) {
+ audioRate.mSpeed = env->GetFloatField(settings, fields.speed);
+ audioRate.mPitch = env->GetFloatField(settings, fields.pitch);
+ audioRate.mFallbackMode =
+ (AudioTimestretchFallbackMode)env->GetIntField(settings, fields.audio_fallback_mode);
+ audioRate.mStretchMode =
+ (AudioTimestretchStretchMode)env->GetIntField(settings, fields.audio_stretch_mode);
+ int set = env->GetIntField(settings, fields.set);
+
+ speedSet = set & fields.set_speed;
+ pitchSet = set & fields.set_pitch;
+ audioFallbackModeSet = set & fields.set_audio_fallback_mode;
+ audioStretchModeSet = set & fields.set_audio_stretch_mode;
+ }
+
+ jobject asJobject(JNIEnv *env, const fields_t& fields) {
+ jobject settings = env->NewObject(fields.clazz, fields.constructID);
+ if (settings == NULL) {
+ return NULL;
+ }
+ env->SetFloatField(settings, fields.speed, (jfloat)audioRate.mSpeed);
+ env->SetFloatField(settings, fields.pitch, (jfloat)audioRate.mPitch);
+ env->SetIntField(settings, fields.audio_fallback_mode, (jint)audioRate.mFallbackMode);
+ env->SetIntField(settings, fields.audio_stretch_mode, (jint)audioRate.mStretchMode);
+ env->SetIntField(
+ settings, fields.set,
+ (speedSet ? fields.set_speed : 0)
+ | (pitchSet ? fields.set_pitch : 0)
+ | (audioFallbackModeSet ? fields.set_audio_fallback_mode : 0)
+ | (audioStretchModeSet ? fields.set_audio_stretch_mode : 0));
+
+ return settings;
+ }
+};
+
+} // namespace android
+
+#endif // _ANDROID_MEDIA_PLAYBACK_SETTINGS_H_