Merge "media: use PlaybackSettings in MediaSync and MediaPlayer"
This commit is contained in:
@@ -15988,6 +15988,7 @@ package android.media {
|
||||
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 @@ package android.media {
|
||||
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 @@ package android.media {
|
||||
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 @@ package android.media {
|
||||
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 {
|
||||
|
||||
@@ -17201,6 +17201,7 @@ package android.media {
|
||||
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 @@ package android.media {
|
||||
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 @@ package android.media {
|
||||
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 @@ package android.media {
|
||||
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 {
|
||||
|
||||
@@ -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.graphics.SurfaceTexture;
|
||||
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 @@ import java.lang.ref.WeakReference;
|
||||
* <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 class MediaPlayer implements SubtitleController.Listener
|
||||
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 @@ public class MediaPlayer implements SubtitleController.Listener
|
||||
* 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 @@ public class MediaPlayer implements SubtitleController.Listener
|
||||
* @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 @@ public class MediaPlayer implements SubtitleController.Listener
|
||||
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 {
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.annotation.IntDef;
|
||||
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 @@ final public class MediaSync {
|
||||
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 @@ final public class MediaSync {
|
||||
* @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>
|
||||
|
||||
@@ -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 @@ struct fields_t {
|
||||
};
|
||||
static fields_t fields;
|
||||
|
||||
static PlaybackSettings::fields_t gPlaybackSettingsFields;
|
||||
|
||||
static Mutex sLock;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -420,15 +424,55 @@ android_media_MediaPlayer_isPlaying(JNIEnv *env, jobject thiz)
|
||||
}
|
||||
|
||||
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 @@ android_media_MediaPlayer_native_init(JNIEnv *env)
|
||||
return;
|
||||
}
|
||||
|
||||
env->DeleteLocalRef(clazz);
|
||||
|
||||
clazz = env->FindClass("android/net/ProxyInfo");
|
||||
if (clazz == NULL) {
|
||||
return;
|
||||
@@ -710,6 +756,10 @@ android_media_MediaPlayer_native_init(JNIEnv *env)
|
||||
|
||||
fields.proxyConfigGetExclusionList =
|
||||
env->GetMethodID(clazz, "getExclusionListAsString", "()Ljava/lang/String;");
|
||||
|
||||
env->DeleteLocalRef(clazz);
|
||||
|
||||
gPlaybackSettingsFields.init(env);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -898,7 +948,8 @@ static JNINativeMethod gMethods[] = {
|
||||
{"_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},
|
||||
|
||||
120
media/jni/android_media_PlaybackSettings.h
Normal file
120
media/jni/android_media_PlaybackSettings.h
Normal file
@@ -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_
|
||||
Reference in New Issue
Block a user