diff options
| -rw-r--r-- | api/current.txt | 25 | ||||
| -rw-r--r-- | api/system-current.txt | 25 | ||||
| -rw-r--r-- | media/java/android/media/MediaPlayer.java | 23 | ||||
| -rw-r--r-- | media/java/android/media/MediaSync.java | 38 | ||||
| -rw-r--r-- | media/java/android/media/SyncSettings.java | 282 | ||||
| -rw-r--r-- | media/jni/Android.mk | 5 | ||||
| -rw-r--r-- | media/jni/android_media_MediaPlayer.cpp | 55 | ||||
| -rw-r--r-- | media/jni/android_media_MediaSync.cpp | 57 | ||||
| -rw-r--r-- | media/jni/android_media_SyncSettings.cpp | 91 | ||||
| -rw-r--r-- | media/jni/android_media_SyncSettings.h | 66 |
10 files changed, 665 insertions, 2 deletions
diff --git a/api/current.txt b/api/current.txt index 8a4d0b6..ccf4cd7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -15990,6 +15990,7 @@ package android.media { method public int getDuration(); method public android.media.PlaybackSettings getPlaybackSettings(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; + method public android.media.SyncSettings getSyncSettings(); method public android.media.MediaPlayer.TrackInfo[] getTrackInfo() throws java.lang.IllegalStateException; method public int getVideoHeight(); method public int getVideoWidth(); @@ -16028,6 +16029,7 @@ package android.media { method public void setPlaybackSettings(android.media.PlaybackSettings); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); + method public void setSyncSettings(android.media.SyncSettings); method public void setVideoScalingMode(int); method public void setVolume(float, float); method public void setWakeMode(android.content.Context, int); @@ -16346,13 +16348,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 void flush(); method public android.media.PlaybackSettings getPlaybackSettings(); + method public android.media.SyncSettings getSyncSettings(); 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); method public void setPlaybackSettings(android.media.PlaybackSettings); + method public void setSyncSettings(android.media.SyncSettings); 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 @@ -16590,6 +16595,26 @@ package android.media { method public abstract void onLoadComplete(android.media.SoundPool, int, int); } + public final class SyncSettings { + ctor public SyncSettings(); + method public android.media.SyncSettings allowDefaults(); + method public int getAudioAdjustMode(); + method public float getFrameRate(); + method public int getSyncSource(); + method public float getTolerance(); + method public android.media.SyncSettings setAudioAdjustMode(int); + method public android.media.SyncSettings setFrameRate(float); + method public android.media.SyncSettings setSyncSource(int); + method public android.media.SyncSettings setTolerance(float); + field public static final int AUDIO_ADJUST_MODE_DEFAULT = 0; // 0x0 + field public static final int AUDIO_ADJUST_MODE_RESAMPLE = 2; // 0x2 + field public static final int AUDIO_ADJUST_MODE_STRETCH = 1; // 0x1 + field public static final int SYNC_SOURCE_AUDIO = 2; // 0x2 + field public static final int SYNC_SOURCE_DEFAULT = 0; // 0x0 + field public static final int SYNC_SOURCE_SYSTEM_CLOCK = 1; // 0x1 + field public static final int SYNC_SOURCE_VSYNC = 3; // 0x3 + } + public class ThumbnailUtils { ctor public ThumbnailUtils(); method public static android.graphics.Bitmap createVideoThumbnail(java.lang.String, int); diff --git a/api/system-current.txt b/api/system-current.txt index 14e9563..877e884 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -17203,6 +17203,7 @@ package android.media { method public int getDuration(); method public android.media.PlaybackSettings getPlaybackSettings(); method public int getSelectedTrack(int) throws java.lang.IllegalStateException; + method public android.media.SyncSettings getSyncSettings(); method public android.media.MediaPlayer.TrackInfo[] getTrackInfo() throws java.lang.IllegalStateException; method public int getVideoHeight(); method public int getVideoWidth(); @@ -17241,6 +17242,7 @@ package android.media { method public void setPlaybackSettings(android.media.PlaybackSettings); method public void setScreenOnWhilePlaying(boolean); method public void setSurface(android.view.Surface); + method public void setSyncSettings(android.media.SyncSettings); method public void setVideoScalingMode(int); method public void setVolume(float, float); method public void setWakeMode(android.content.Context, int); @@ -17561,13 +17563,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 void flush(); method public android.media.PlaybackSettings getPlaybackSettings(); + method public android.media.SyncSettings getSyncSettings(); 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); method public void setPlaybackSettings(android.media.PlaybackSettings); + method public void setSyncSettings(android.media.SyncSettings); 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 @@ -17805,6 +17810,26 @@ package android.media { method public abstract void onLoadComplete(android.media.SoundPool, int, int); } + public final class SyncSettings { + ctor public SyncSettings(); + method public android.media.SyncSettings allowDefaults(); + method public int getAudioAdjustMode(); + method public float getFrameRate(); + method public int getSyncSource(); + method public float getTolerance(); + method public android.media.SyncSettings setAudioAdjustMode(int); + method public android.media.SyncSettings setFrameRate(float); + method public android.media.SyncSettings setSyncSource(int); + method public android.media.SyncSettings setTolerance(float); + field public static final int AUDIO_ADJUST_MODE_DEFAULT = 0; // 0x0 + field public static final int AUDIO_ADJUST_MODE_RESAMPLE = 2; // 0x2 + field public static final int AUDIO_ADJUST_MODE_STRETCH = 1; // 0x1 + field public static final int SYNC_SOURCE_AUDIO = 2; // 0x2 + field public static final int SYNC_SOURCE_DEFAULT = 0; // 0x0 + field public static final int SYNC_SOURCE_SYSTEM_CLOCK = 1; // 0x1 + field public static final int SYNC_SOURCE_VSYNC = 3; // 0x3 + } + public class ThumbnailUtils { ctor public ThumbnailUtils(); method public static android.graphics.Bitmap createVideoThumbnail(java.lang.String, int); diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java index 85c6c67..f446d6c 100644 --- a/media/java/android/media/MediaPlayer.java +++ b/media/java/android/media/MediaPlayer.java @@ -50,6 +50,7 @@ import android.media.SubtitleController; import android.media.SubtitleController.Anchor; import android.media.SubtitleData; import android.media.SubtitleTrack.RenderingWidget; +import android.media.SyncSettings; import com.android.internal.app.IAppOpsService; @@ -1447,6 +1448,28 @@ public class MediaPlayer implements SubtitleController.Listener public native PlaybackSettings getPlaybackSettings(); /** + * Sets A/V sync mode. + * + * @param settings the A/V sync settings to apply + * + * @throws IllegalStateException if the internal player engine has not been + * initialized. + * @throws IllegalArgumentException if settings are not supported. + */ + public native void setSyncSettings(@NonNull SyncSettings settings); + + /** + * Gets the A/V sync mode. + * + * @return the A/V sync settings + * + * @throws IllegalStateException if the internal player engine has not been + * initialized. + */ + @NonNull + public native SyncSettings getSyncSettings(); + + /** * Seeks to specified time position. * * @param msec the offset in milliseconds from the start to seek to diff --git a/media/java/android/media/MediaSync.java b/media/java/android/media/MediaSync.java index cc894cb..bfcefb4 100644 --- a/media/java/android/media/MediaSync.java +++ b/media/java/android/media/MediaSync.java @@ -441,6 +441,44 @@ final public class MediaSync { private native final void native_setPlaybackRate(float rate); + /** + * Sets A/V sync mode. + * + * @param settings the A/V sync settings to apply + * + * @throws IllegalStateException if the internal player engine has not been + * initialized. + * @throws IllegalArgumentException if settings are not supported. + */ + public native void setSyncSettings(@NonNull SyncSettings settings); + + /** + * Gets the A/V sync mode. + * + * @return the A/V sync settings + * + * @throws IllegalStateException if the internal player engine has not been + * initialized. + */ + @NonNull + public native SyncSettings getSyncSettings(); + + /** + * Flushes all buffers from the sync object. + * <p> + * No callbacks are received for the flushed buffers. + * + * @throws IllegalStateException if the internal player engine has not been + * initialized. + */ + public void flush() { + synchronized(mAudioLock) { + mAudioBuffers.clear(); + mCallbackHandler.removeCallbacksAndMessages(null); + } + // TODO implement this for surface buffers. + } + /** * Get current playback position. * <p> diff --git a/media/java/android/media/SyncSettings.java b/media/java/android/media/SyncSettings.java new file mode 100644 index 0000000..9740147 --- /dev/null +++ b/media/java/android/media/SyncSettings.java @@ -0,0 +1,282 @@ +/* + * 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 A/V sync settings. + * + * Used by {@link MediaSync} {link MediaSync#getSyncSettings()} and + * {link MediaSync#setSyncSettings(SyncSettings)} + * to control A/V sync behavior. + * <p> <strong>audio adjust mode:</strong> + * select handling of audio track when changing playback speed due to sync. + * <ul> + * <li> {@link SyncSettings#AUDIO_ADJUST_MODE_DEFAULT}: + * System will determine best handling. </li> + * <li> {@link SyncSettings#AUDIO_ADJUST_MODE_STRETCH}: + * Change the speed of audio playback without altering its pitch.</li> + * <li> {@link SyncSettings#AUDIO_ADJUST_MODE_RESAMPLE}: + * Change the speed of audio playback by resampling the audio.</li> + * </ul> + * <p> <strong>sync source:</strong> select + * clock source for sync. + * <ul> + * <li> {@link SyncSettings#SYNC_SOURCE_DEFAULT}: + * System will determine best selection.</li> + * <li> {@link SyncSettings#SYNC_SOURCE_SYSTEM_CLOCK}: + * Use system clock for sync source.</li> + * <li> {@link SyncSettings#SYNC_SOURCE_AUDIO}: + * Use audio track for sync source.</li> + * <li> {@link SyncSettings#SYNC_SOURCE_VSYNC}: + * Syncronize media to vsync.</li> + * </ul> + * <p> <strong>tolerance:</strong> specifies the amount of allowed playback rate + * change to keep media in sync with the sync source. The handling of this depends + * on the sync source. + * <p> <strong>frameRate:</strong> initial hint for video frame rate. Used when + * sync source is vsync. + */ +public final class SyncSettings { + /** @hide */ + @IntDef( + value = { + SYNC_SOURCE_DEFAULT, + SYNC_SOURCE_SYSTEM_CLOCK, + SYNC_SOURCE_AUDIO, + SYNC_SOURCE_VSYNC, + } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface SyncSource {} + + /** + * Use the default sync source (default). If media has video, the sync renders to a + * surface that directly renders to a display, and tolerance is non zero (e.g. not + * less than 0.001) vsync source is used for clock source. Otherwise, if media has + * audio, audio track is used. Finally, if media has no audio, system clock is used. + */ + public static final int SYNC_SOURCE_DEFAULT = 0; + + /** + * Use system monotonic clock for sync source. + * + * @see System#nanoTime + */ + public static final int SYNC_SOURCE_SYSTEM_CLOCK = 1; + + /** + * Use audio track for sync source. This requires audio data and an audio track. + * + * @see AudioTrack#getTimeStamp + */ + public static final int SYNC_SOURCE_AUDIO = 2; + + /** + * Use vsync as the sync source. This requires video data and an output surface that + * directly renders to the display, e.g. {@link android.view.SurfaceView} + * <p> + * This mode allows smoother playback experience by adjusting the playback speed + * to match the vsync rate, e.g. playing 30fps content on a 59.94Hz display. + * When using this mode, the tolerance should be set to greater than 0 (e.g. at least + * 1/1000), so that the playback speed can actually be adjusted. + * <p> + * This mode can also be used to play 25fps content on a 60Hz display using + * a 2:3 pulldown (basically playing the content at 24fps), which results on + * better playback experience on most devices. In this case the tolerance should be + * at least (1/24). + * + * @see android.view.Choreographer.FrameCallback#doFrame + * @see android.view.Display#getAppVsyncOffsetNanos + */ + public static final int SYNC_SOURCE_VSYNC = 3; + + /** @hide */ + @IntDef( + value = { + AUDIO_ADJUST_MODE_DEFAULT, + AUDIO_ADJUST_MODE_STRETCH, + AUDIO_ADJUST_MODE_RESAMPLE, + } + ) + @Retention(RetentionPolicy.SOURCE) + public @interface AudioAdjustMode {} + + /** + * System will determine best handling of audio for playback rate + * adjustments. + * <p> + * Used by default. This will make audio play faster or slower as required + * by the sync source without changing its pitch; however, system may fall + * back to some other method (e.g. change the pitch, or mute the audio) if + * time stretching is no longer supported for the playback rate. + */ + public static final int AUDIO_ADJUST_MODE_DEFAULT = 0; + + /** + * Time stretch audio when playback rate must be adjusted. + * <p> + * This will make audio play faster or slower as required by the sync source + * without changing its pitch, as long as it is supported for the playback + * rate. + * + * @see MediaSync#PLAYBACK_RATE_AUDIO_MODE_STRETCH + * @see MediaPlayer#PLAYBACK_RATE_AUDIO_MODE_STRETCH + */ + public static final int AUDIO_ADJUST_MODE_STRETCH = 1; + + /** + * Resample audio when playback rate must be adjusted. + * <p> + * This will make audio play faster or slower as required by the sync source + * by changing its pitch (making it lower to play slower, and higher to play + * faster.) + * + * @see MediaSync#PLAYBACK_RATE_AUDIO_MODE_RESAMPLE + * @see MediaPlayer#PLAYBACK_RATE_AUDIO_MODE_RESAMPLE + */ + public static final int AUDIO_ADJUST_MODE_RESAMPLE = 2; + + // flags to indicate which settings are actually set + private static final int SET_SYNC_SOURCE = 1 << 0; + private static final int SET_AUDIO_ADJUST_MODE = 1 << 1; + private static final int SET_TOLERANCE = 1 << 2; + private static final int SET_FRAME_RATE = 1 << 3; + private int mSet = 0; + + // settings + private int mAudioAdjustMode = AUDIO_ADJUST_MODE_STRETCH; + private int mSyncSource = SYNC_SOURCE_DEFAULT; + private float mTolerance = 0.f; + private float mFrameRate = 0.f; + + /** + * 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>SyncSettings</code> instance. + */ + public SyncSettings allowDefaults() { + mSet |= SET_SYNC_SOURCE | SET_AUDIO_ADJUST_MODE | SET_TOLERANCE; + return this; + } + + /** + * Sets the audio adjust mode. + * @param audioAdjustMode + * @return this <code>SyncSettings</code> instance. + */ + public SyncSettings setAudioAdjustMode(@AudioAdjustMode int audioAdjustMode) { + mAudioAdjustMode = audioAdjustMode; + mSet |= SET_AUDIO_ADJUST_MODE; + return this; + } + + /** + * Retrieves the audio adjust mode. + * @return audio adjust mode + * @throws IllegalStateException if the audio adjust mode is not set. + */ + public @AudioAdjustMode int getAudioAdjustMode() { + if ((mSet & SET_AUDIO_ADJUST_MODE) == 0) { + throw new IllegalStateException("audio adjust mode not set"); + } + return mAudioAdjustMode; + } + + /** + * Sets the sync source. + * @param syncSource + * @return this <code>SyncSettings</code> instance. + */ + public SyncSettings setSyncSource(@SyncSource int syncSource) { + mSyncSource = syncSource; + mSet |= SET_SYNC_SOURCE; + return this; + } + + /** + * Retrieves the sync source. + * @return sync source + * @throws IllegalStateException if the sync source is not set. + */ + public @SyncSource int getSyncSource() { + if ((mSet & SET_SYNC_SOURCE) == 0) { + throw new IllegalStateException("sync source not set"); + } + return mSyncSource; + } + + /** + * Sets the tolerance. The default tolerance is 0. + * @param tolerance A non-negative number representing + * the maximum deviation of the playback rate from the playback rate + * set. ({@code abs(actual_rate - set_rate) / set_rate}) + * @return this <code>SyncSettings</code> instance. + */ + public SyncSettings setTolerance(float tolerance) { + mTolerance = tolerance; + mSet |= SET_TOLERANCE; + return this; + } + + /** + * Retrieves the tolerance factor. + * @return tolerance factor. A non-negative number representing + * the maximum deviation of the playback rate from the playback rate + * set. ({@code abs(actual_rate - set_rate) / set_rate}) + * @throws IllegalStateException if tolerance is not set. + */ + public float getTolerance() { + if ((mSet & SET_TOLERANCE) == 0) { + throw new IllegalStateException("tolerance not set"); + } + return mTolerance; + } + + /** + * Sets the video frame rate hint to be used. By default the frame rate is unspecified. + * @param frameRate A non-negative number used as an initial hint on + * the video frame rate to be used when using vsync as the sync source. + * @return this <code>SyncSettings</code> instance. + */ + public SyncSettings setFrameRate(float frameRate) { + mFrameRate = frameRate; + mSet |= SET_FRAME_RATE; + return this; + } + + /** + * Retrieves the video frame rate hint. + * @return frame rate factor. A non-negative number representing + * the maximum deviation of the playback rate from the playback rate + * set. ({@code abs(actual_rate - set_rate) / set_rate}) + * @throws IllegalStateException if frame rate is not set. + */ + public float getFrameRate() { + if ((mSet & SET_FRAME_RATE) == 0) { + throw new IllegalStateException("frame rate not set"); + } + return mFrameRate; + } + +} diff --git a/media/jni/Android.mk b/media/jni/Android.mk index c8464c7..dbb53b4 100644 --- a/media/jni/Android.mk +++ b/media/jni/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ + android_media_AmrInputStream.cpp \ android_media_ImageWriter.cpp \ android_media_ImageReader.cpp \ android_media_MediaCrypto.cpp \ @@ -14,12 +15,12 @@ LOCAL_SRC_FILES:= \ android_media_MediaMetadataRetriever.cpp \ android_media_MediaMuxer.cpp \ android_media_MediaPlayer.cpp \ + android_media_MediaProfiles.cpp \ android_media_MediaRecorder.cpp \ android_media_MediaScanner.cpp \ android_media_MediaSync.cpp \ android_media_ResampleInputStream.cpp \ - android_media_MediaProfiles.cpp \ - android_media_AmrInputStream.cpp \ + android_media_SyncSettings.cpp \ android_media_Utils.cpp \ android_mtp_MtpDatabase.cpp \ android_mtp_MtpDevice.cpp \ diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp index b79a6bb..2c61779 100644 --- a/media/jni/android_media_MediaPlayer.cpp +++ b/media/jni/android_media_MediaPlayer.cpp @@ -39,6 +39,7 @@ #include "utils/String8.h" #include "android_media_MediaDataSource.h" #include "android_media_PlaybackSettings.h" +#include "android_media_SyncSettings.h" #include "android_media_Utils.h" #include "android_os_Parcel.h" @@ -69,6 +70,7 @@ struct fields_t { static fields_t fields; static PlaybackSettings::fields_t gPlaybackSettingsFields; +static SyncSettings::fields_t gSyncSettingsFields; static Mutex sLock; @@ -476,6 +478,56 @@ android_media_MediaPlayer_getPlaybackSettings(JNIEnv *env, jobject thiz) } static void +android_media_MediaPlayer_setSyncSettings(JNIEnv *env, jobject thiz, jobject settings) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return; + } + + SyncSettings scs; + scs.fillFromJobject(env, gSyncSettingsFields, settings); + ALOGV("setSyncSettings: %d:%d %d:%d %d:%f %d:%f", + scs.syncSourceSet, scs.syncSource, + scs.audioAdjustModeSet, scs.audioAdjustMode, + scs.toleranceSet, scs.tolerance, + scs.frameRateSet, scs.frameRate); + + // TODO: pass sync settings to mediaplayer when it supports it + // process_media_player_call(env, thiz, mp->setSyncSettings(scs), NULL, NULL); +} + +static jobject +android_media_MediaPlayer_getSyncSettings(JNIEnv *env, jobject thiz) +{ + sp<MediaPlayer> mp = getMediaPlayer(env, thiz); + if (mp == NULL) { + jniThrowException(env, "java/lang/IllegalStateException", NULL); + return NULL; + } + + SyncSettings scs; + scs.syncSource = 0; // SYNC_SOURCE_DEFAULT + scs.audioAdjustMode = 0; // AUDIO_ADJUST_MODE_DEFAULT + scs.tolerance = 0.f; + scs.frameRate = 0.f; + + // TODO: get this from mediaplayer when it supports it + // process_media_player_call( + // env, thiz, mp->getSyncSettings(&scs), NULL, NULL); + ALOGV("getSyncSettings: %d %d %f %f", + scs.syncSource, scs.audioAdjustMode, scs.tolerance, scs.frameRate); + + scs.syncSourceSet = true; + scs.audioAdjustModeSet = true; + scs.toleranceSet = true; + scs.frameRateSet = false; + + return scs.asJobject(env, gSyncSettingsFields); +} + +static void android_media_MediaPlayer_seekTo(JNIEnv *env, jobject thiz, jint msec) { sp<MediaPlayer> mp = getMediaPlayer(env, thiz); @@ -760,6 +812,7 @@ android_media_MediaPlayer_native_init(JNIEnv *env) env->DeleteLocalRef(clazz); gPlaybackSettingsFields.init(env); + gSyncSettingsFields.init(env); } static void @@ -950,6 +1003,8 @@ static JNINativeMethod gMethods[] = { {"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight}, {"setPlaybackSettings", "(Landroid/media/PlaybackSettings;)V", (void *)android_media_MediaPlayer_setPlaybackSettings}, {"getPlaybackSettings", "()Landroid/media/PlaybackSettings;", (void *)android_media_MediaPlayer_getPlaybackSettings}, + {"setSyncSettings", "(Landroid/media/SyncSettings;)V", (void *)android_media_MediaPlayer_setSyncSettings}, + {"getSyncSettings", "()Landroid/media/SyncSettings;", (void *)android_media_MediaPlayer_getSyncSettings}, {"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_MediaSync.cpp b/media/jni/android_media_MediaSync.cpp index e167f83..72dacdf 100644 --- a/media/jni/android_media_MediaSync.cpp +++ b/media/jni/android_media_MediaSync.cpp @@ -21,6 +21,7 @@ #include "android_media_MediaSync.h" #include "android_media_AudioTrack.h" +#include "android_media_SyncSettings.h" #include "android_runtime/AndroidRuntime.h" #include "android_runtime/android_view_Surface.h" #include "jni.h" @@ -46,6 +47,7 @@ struct fields_t { }; static fields_t gFields; +static SyncSettings::fields_t gSyncSettingsFields; //////////////////////////////////////////////////////////////////////////////// @@ -266,6 +268,55 @@ static jboolean android_media_MediaSync_native_getTimestamp( return JNI_TRUE; } +static void +android_media_MediaSync_setSyncSettings(JNIEnv *env, jobject thiz, jobject settings) +{ + sp<JMediaSync> sync = getMediaSync(env, thiz); + if (sync == NULL) { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return; + } + + SyncSettings scs; + scs.fillFromJobject(env, gSyncSettingsFields, settings); + ALOGV("setSyncSettings: %d:%d %d:%d %d:%f %d:%f", + scs.syncSourceSet, scs.syncSource, + scs.audioAdjustModeSet, scs.audioAdjustMode, + scs.toleranceSet, scs.tolerance, + scs.frameRateSet, scs.frameRate); + + // TODO: pass sync settings to mediasync when it supports it +} + +static jobject +android_media_MediaSync_getSyncSettings(JNIEnv *env, jobject thiz) +{ + sp<JMediaSync> sync = getMediaSync(env, thiz); + if (sync == NULL) { + throwExceptionAsNecessary(env, INVALID_OPERATION); + return NULL; + } + + SyncSettings scs; + scs.syncSource = 0; // SYNC_SOURCE_DEFAULT + scs.audioAdjustMode = 0; // AUDIO_ADJUST_MODE_DEFAULT + scs.tolerance = 0.f; + scs.frameRate = 0.f; + + // TODO: get this from mediaplayer when it supports it + // process_media_player_call( + // env, thiz, mp->getSyncSettings(&scs), NULL, NULL); + ALOGV("getSyncSettings: %d %d %f %f", + scs.syncSource, scs.audioAdjustMode, scs.tolerance, scs.frameRate); + + scs.syncSourceSet = true; + scs.audioAdjustModeSet = true; + scs.toleranceSet = true; + scs.frameRateSet = false; + + return scs.asJobject(env, gSyncSettingsFields); +} + static void android_media_MediaSync_native_init(JNIEnv *env) { ScopedLocalRef<jclass> clazz(env, env->FindClass("android/media/MediaSync")); CHECK(clazz.get() != NULL); @@ -287,6 +338,8 @@ static void android_media_MediaSync_native_init(JNIEnv *env) { gFields.mediaTimestampClockRateID = env->GetFieldID(clazz.get(), "clockRate", "F"); CHECK(gFields.mediaTimestampClockRateID != NULL); + + gSyncSettingsFields.init(env); } static void android_media_MediaSync_native_setup(JNIEnv *env, jobject thiz) { @@ -342,6 +395,10 @@ static JNINativeMethod gMethods[] = { { "native_setPlaybackRate", "(F)V", (void *)android_media_MediaSync_native_setPlaybackRate }, + { "setSyncSettings", "(Landroid/media/SyncSettings;)V", (void *)android_media_MediaSync_setSyncSettings}, + + { "getSyncSettings", "()Landroid/media/SyncSettings;", (void *)android_media_MediaSync_getSyncSettings}, + { "native_finalize", "()V", (void *)android_media_MediaSync_native_finalize }, }; diff --git a/media/jni/android_media_SyncSettings.cpp b/media/jni/android_media_SyncSettings.cpp new file mode 100644 index 0000000..2f0605e --- /dev/null +++ b/media/jni/android_media_SyncSettings.cpp @@ -0,0 +1,91 @@ +/* + * 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. + */ + +#include "android_media_SyncSettings.h" + +#include "JNIHelp.h" + +namespace android { + +void SyncSettings::fields_t::init(JNIEnv *env) { + jclass lclazz = env->FindClass("android/media/SyncSettings"); + if (lclazz == NULL) { + return; + } + + clazz = (jclass)env->NewGlobalRef(lclazz); + if (clazz == NULL) { + return; + } + + constructID = env->GetMethodID(clazz, "<init>", "()V"); + + sync_source = env->GetFieldID(clazz, "mSyncSource", "I"); + audio_adjust_mode = env->GetFieldID(clazz, "mAudioAdjustMode", "I"); + tolerance = env->GetFieldID(clazz, "mTolerance", "F"); + frame_rate = env->GetFieldID(clazz, "mFrameRate", "F"); + set = env->GetFieldID(clazz, "mSet", "I"); + + set_sync_source = + env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "SET_SYNC_SOURCE", "I")); + set_audio_adjust_mode = env->GetStaticIntField( + clazz, env->GetStaticFieldID(clazz, "SET_AUDIO_ADJUST_MODE", "I")); + set_tolerance = + env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "SET_TOLERANCE", "I")); + set_frame_rate = + env->GetStaticIntField(clazz, env->GetStaticFieldID(clazz, "SET_FRAME_RATE", "I")); + + env->DeleteLocalRef(lclazz); +} + +void SyncSettings::fields_t::exit(JNIEnv *env) { + env->DeleteGlobalRef(clazz); + clazz = NULL; +} + +void SyncSettings::fillFromJobject(JNIEnv *env, const fields_t& fields, jobject settings) { + syncSource = env->GetIntField(settings, fields.sync_source); + audioAdjustMode = env->GetIntField(settings, fields.audio_adjust_mode); + tolerance = env->GetFloatField(settings, fields.tolerance); + frameRate = env->GetFloatField(settings, fields.frame_rate); + int set = env->GetIntField(settings, fields.set); + + syncSourceSet = set & fields.set_sync_source; + audioAdjustModeSet = set & fields.set_audio_adjust_mode; + toleranceSet = set & fields.set_tolerance; + frameRateSet = set & fields.set_frame_rate; +} + +jobject SyncSettings::asJobject(JNIEnv *env, const fields_t& fields) { + jobject settings = env->NewObject(fields.clazz, fields.constructID); + if (settings == NULL) { + return NULL; + } + env->SetIntField(settings, fields.sync_source, (jint)syncSource); + env->SetIntField(settings, fields.audio_adjust_mode, (jint)audioAdjustMode); + env->SetFloatField(settings, fields.tolerance, (jfloat)tolerance); + env->SetFloatField(settings, fields.frame_rate, (jfloat)frameRate); + env->SetIntField( + settings, fields.set, + (syncSourceSet ? fields.set_sync_source : 0) + | (audioAdjustModeSet ? fields.set_audio_adjust_mode : 0) + | (toleranceSet ? fields.set_tolerance : 0) + | (frameRateSet ? fields.set_frame_rate : 0)); + + return settings; +} + +} // namespace android diff --git a/media/jni/android_media_SyncSettings.h b/media/jni/android_media_SyncSettings.h new file mode 100644 index 0000000..586533f --- /dev/null +++ b/media/jni/android_media_SyncSettings.h @@ -0,0 +1,66 @@ +/* + * 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_SYNC_SETTINGS_H_ +#define _ANDROID_MEDIA_SYNC_SETTINGS_H_ + +#include "jni.h" + +namespace android { + +struct SyncSettings { + // keep this here until it is implemented + int syncSource; + int audioAdjustMode; + float tolerance; + float frameRate; + + bool syncSourceSet; + bool audioAdjustModeSet; + bool toleranceSet; + bool frameRateSet; + + struct fields_t { + jclass clazz; + jmethodID constructID; + + jfieldID sync_source; + jfieldID audio_adjust_mode; + jfieldID tolerance; + jfieldID frame_rate; + jfieldID set; + jint set_sync_source; + jint set_audio_adjust_mode; + jint set_tolerance; + jint set_frame_rate; + + // initializes fields + void init(JNIEnv *env); + + // releases global references held + void exit(JNIEnv *env); + }; + + // fills this from an android.media.SyncSettings object + void fillFromJobject(JNIEnv *env, const fields_t& fields, jobject settings); + + // returns this as a android.media.SyncSettings object + jobject asJobject(JNIEnv *env, const fields_t& fields); +}; + +} // namespace android + +#endif // _ANDROID_MEDIA_SYNC_SETTINGS_H_ |
