1/*
2 * Copyright 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
19import java.lang.annotation.Retention;
20import java.lang.annotation.RetentionPolicy;
21
22import android.annotation.IntDef;
23
24/**
25 * Structure for common A/V sync params.
26 *
27 * Used by {@link MediaSync} {link MediaSync#getSyncParams()} and
28 * {link MediaSync#setSyncParams(SyncParams)}
29 * to control A/V sync behavior.
30 * <p> <strong>audio adjust mode:</strong>
31 * select handling of audio track when changing playback speed due to sync.
32 * <ul>
33 * <li> {@link SyncParams#AUDIO_ADJUST_MODE_DEFAULT}:
34 *   System will determine best handling. </li>
35 * <li> {@link SyncParams#AUDIO_ADJUST_MODE_STRETCH}:
36 *   Change the speed of audio playback without altering its pitch.</li>
37 * <li> {@link SyncParams#AUDIO_ADJUST_MODE_RESAMPLE}:
38 *   Change the speed of audio playback by resampling the audio.</li>
39 * </ul>
40 * <p> <strong>sync source:</strong> select
41 * clock source for sync.
42 * <ul>
43 * <li> {@link SyncParams#SYNC_SOURCE_DEFAULT}:
44 *   System will determine best selection.</li>
45 * <li> {@link SyncParams#SYNC_SOURCE_SYSTEM_CLOCK}:
46 *   Use system clock for sync source.</li>
47 * <li> {@link SyncParams#SYNC_SOURCE_AUDIO}:
48 *   Use audio track for sync source.</li>
49 * <li> {@link SyncParams#SYNC_SOURCE_VSYNC}:
50 *   Syncronize media to vsync.</li>
51 * </ul>
52 * <p> <strong>tolerance:</strong> specifies the amount of allowed playback rate
53 * change to keep media in sync with the sync source. The handling of this depends
54 * on the sync source, but must not be negative, and must be less than one.
55 * <p> <strong>frameRate:</strong> initial hint for video frame rate. Used when
56 * sync source is vsync. Negative values can be used to clear a previous hint.
57 */
58public final class SyncParams {
59    /** @hide */
60    @IntDef(
61        value = {
62                SYNC_SOURCE_DEFAULT,
63                SYNC_SOURCE_SYSTEM_CLOCK,
64                SYNC_SOURCE_AUDIO,
65                SYNC_SOURCE_VSYNC,
66        }
67    )
68    @Retention(RetentionPolicy.SOURCE)
69    public @interface SyncSource {}
70
71    /**
72     * Use the default sync source (default). If media has video, the sync renders to a
73     * surface that directly renders to a display, and tolerance is non zero (e.g. not
74     * less than 0.001) vsync source is used for clock source.  Otherwise, if media has
75     * audio, audio track is used. Finally, if media has no audio, system clock is used.
76     */
77    public static final int SYNC_SOURCE_DEFAULT = 0;
78
79    /**
80     * Use system monotonic clock for sync source.
81     *
82     * @see System#nanoTime
83     */
84    public static final int SYNC_SOURCE_SYSTEM_CLOCK = 1;
85
86    /**
87     * Use audio track for sync source. This requires audio data and an audio track.
88     *
89     * @see AudioTrack#getTimeStamp
90     */
91    public static final int SYNC_SOURCE_AUDIO = 2;
92
93    /**
94     * Use vsync as the sync source. This requires video data and an output surface that
95     * directly renders to the display, e.g. {@link android.view.SurfaceView}
96     * <p>
97     * This mode allows smoother playback experience by adjusting the playback speed
98     * to match the vsync rate, e.g. playing 30fps content on a 59.94Hz display.
99     * When using this mode, the tolerance should be set to greater than 0 (e.g. at least
100     * 1/1000), so that the playback speed can actually be adjusted.
101     * <p>
102     * This mode can also be used to play 25fps content on a 60Hz display using
103     * a 2:3 pulldown (basically playing the content at 24fps), which results on
104     * better playback experience on most devices. In this case the tolerance should be
105     * at least (1/24).
106     *
107     * @see android.view.Choreographer.FrameCallback#doFrame
108     * @see android.view.Display#getAppVsyncOffsetNanos
109     */
110    public static final int SYNC_SOURCE_VSYNC = 3;
111
112    /** @hide */
113    @IntDef(
114        value = {
115                AUDIO_ADJUST_MODE_DEFAULT,
116                AUDIO_ADJUST_MODE_STRETCH,
117                AUDIO_ADJUST_MODE_RESAMPLE,
118        }
119    )
120    @Retention(RetentionPolicy.SOURCE)
121    public @interface AudioAdjustMode {}
122
123    /**
124     * System will determine best handling of audio for playback rate
125     * adjustments.
126     * <p>
127     * Used by default. This will make audio play faster or slower as required
128     * by the sync source without changing its pitch; however, system may fall
129     * back to some other method (e.g. change the pitch, or mute the audio) if
130     * time stretching is no longer supported for the playback rate.
131     */
132    public static final int AUDIO_ADJUST_MODE_DEFAULT = 0;
133
134    /**
135     * Time stretch audio when playback rate must be adjusted.
136     * <p>
137     * This will make audio play faster or slower as required by the sync source
138     * without changing its pitch, as long as it is supported for the playback
139     * rate.
140     *
141     * @see MediaSync#PLAYBACK_RATE_AUDIO_MODE_STRETCH
142     * @see MediaPlayer#PLAYBACK_RATE_AUDIO_MODE_STRETCH
143     */
144    public static final int AUDIO_ADJUST_MODE_STRETCH = 1;
145
146    /**
147     * Resample audio when playback rate must be adjusted.
148     * <p>
149     * This will make audio play faster or slower as required by the sync source
150     * by changing its pitch (making it lower to play slower, and higher to play
151     * faster.)
152     *
153     * @see MediaSync#PLAYBACK_RATE_AUDIO_MODE_RESAMPLE
154     * @see MediaPlayer#PLAYBACK_RATE_AUDIO_MODE_RESAMPLE
155     */
156    public static final int AUDIO_ADJUST_MODE_RESAMPLE = 2;
157
158    // flags to indicate which params are actually set
159    private static final int SET_SYNC_SOURCE         = 1 << 0;
160    private static final int SET_AUDIO_ADJUST_MODE   = 1 << 1;
161    private static final int SET_TOLERANCE           = 1 << 2;
162    private static final int SET_FRAME_RATE          = 1 << 3;
163    private int mSet = 0;
164
165    // params
166    private int mAudioAdjustMode = AUDIO_ADJUST_MODE_DEFAULT;
167    private int mSyncSource = SYNC_SOURCE_DEFAULT;
168    private float mTolerance = 0.f;
169    private float mFrameRate = 0.f;
170
171    /**
172     * Allows defaults to be returned for properties not set.
173     * Otherwise a {@link java.lang.IllegalArgumentException} exception
174     * is raised when getting those properties
175     * which have defaults but have never been set.
176     * @return this <code>SyncParams</code> instance.
177     */
178    public SyncParams allowDefaults() {
179        mSet |= SET_SYNC_SOURCE | SET_AUDIO_ADJUST_MODE | SET_TOLERANCE;
180        return this;
181    }
182
183    /**
184     * Sets the audio adjust mode.
185     * @param audioAdjustMode
186     * @return this <code>SyncParams</code> instance.
187     */
188    public SyncParams setAudioAdjustMode(@AudioAdjustMode int audioAdjustMode) {
189        mAudioAdjustMode = audioAdjustMode;
190        mSet |= SET_AUDIO_ADJUST_MODE;
191        return this;
192    }
193
194    /**
195     * Retrieves the audio adjust mode.
196     * @return audio adjust mode
197     * @throws IllegalStateException if the audio adjust mode is not set.
198     */
199    public @AudioAdjustMode int getAudioAdjustMode() {
200        if ((mSet & SET_AUDIO_ADJUST_MODE) == 0) {
201            throw new IllegalStateException("audio adjust mode not set");
202        }
203        return mAudioAdjustMode;
204    }
205
206    /**
207     * Sets the sync source.
208     * @param syncSource
209     * @return this <code>SyncParams</code> instance.
210     */
211    public SyncParams setSyncSource(@SyncSource int syncSource) {
212        mSyncSource = syncSource;
213        mSet |= SET_SYNC_SOURCE;
214        return this;
215    }
216
217    /**
218     * Retrieves the sync source.
219     * @return sync source
220     * @throws IllegalStateException if the sync source is not set.
221     */
222    public @SyncSource int getSyncSource() {
223        if ((mSet & SET_SYNC_SOURCE) == 0) {
224            throw new IllegalStateException("sync source not set");
225        }
226        return mSyncSource;
227    }
228
229    /**
230     * Sets the tolerance. The default tolerance is platform specific, but is never more than 1/24.
231     * @param tolerance A non-negative number representing
232     *     the maximum deviation of the playback rate from the playback rate
233     *     set. ({@code abs(actual_rate - set_rate) / set_rate})
234     * @return this <code>SyncParams</code> instance.
235     * @throws InvalidArgumentException if the tolerance is negative, or not less than one
236     */
237    public SyncParams setTolerance(float tolerance) {
238        if (tolerance < 0.f || tolerance >= 1.f) {
239            throw new IllegalArgumentException("tolerance must be less than one and non-negative");
240        }
241        mTolerance = tolerance;
242        mSet |= SET_TOLERANCE;
243        return this;
244    }
245
246    /**
247     * Retrieves the tolerance factor.
248     * @return tolerance factor. A non-negative number representing
249     *     the maximum deviation of the playback rate from the playback rate
250     *     set. ({@code abs(actual_rate - set_rate) / set_rate})
251     * @throws IllegalStateException if tolerance is not set.
252     */
253    public float getTolerance() {
254        if ((mSet & SET_TOLERANCE) == 0) {
255            throw new IllegalStateException("tolerance not set");
256        }
257        return mTolerance;
258    }
259
260    /**
261     * Sets the video frame rate hint to be used. By default the frame rate is unspecified.
262     * @param frameRate A non-negative number used as an initial hint on
263     *     the video frame rate to be used when using vsync as the sync source. A negative
264     *     number is used to clear a previous hint.
265     * @return this <code>SyncParams</code> instance.
266     */
267    public SyncParams setFrameRate(float frameRate) {
268        mFrameRate = frameRate;
269        mSet |= SET_FRAME_RATE;
270        return this;
271    }
272
273    /**
274     * Retrieves the video frame rate hint.
275     * @return frame rate factor. A non-negative number representing
276     *     the maximum deviation of the playback rate from the playback rate
277     *     set. ({@code abs(actual_rate - set_rate) / set_rate}), or a negative
278     *     number representing the desire to clear a previous hint using these params.
279     * @throws IllegalStateException if frame rate is not set.
280     */
281    public float getFrameRate() {
282        if ((mSet & SET_FRAME_RATE) == 0) {
283            throw new IllegalStateException("frame rate not set");
284        }
285        return mFrameRate;
286    }
287
288}
289