summaryrefslogtreecommitdiff
path: root/android/media/SyncParams.java
blob: 9f6bfe14bd616d08b4e0871a282796a6ee28e6c3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*
 * 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 params.
 *
 * Used by {@link MediaSync} {link MediaSync#getSyncParams()} and
 * {link MediaSync#setSyncParams(SyncParams)}
 * 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 SyncParams#AUDIO_ADJUST_MODE_DEFAULT}:
 *   System will determine best handling. </li>
 * <li> {@link SyncParams#AUDIO_ADJUST_MODE_STRETCH}:
 *   Change the speed of audio playback without altering its pitch.</li>
 * <li> {@link SyncParams#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 SyncParams#SYNC_SOURCE_DEFAULT}:
 *   System will determine best selection.</li>
 * <li> {@link SyncParams#SYNC_SOURCE_SYSTEM_CLOCK}:
 *   Use system clock for sync source.</li>
 * <li> {@link SyncParams#SYNC_SOURCE_AUDIO}:
 *   Use audio track for sync source.</li>
 * <li> {@link SyncParams#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, but must not be negative, and must be less than one.
 * <p> <strong>frameRate:</strong> initial hint for video frame rate. Used when
 * sync source is vsync. Negative values can be used to clear a previous hint.
 */
public final class SyncParams {
    /** @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 params 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;

    // params
    private int mAudioAdjustMode = AUDIO_ADJUST_MODE_DEFAULT;
    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>SyncParams</code> instance.
     */
    public SyncParams allowDefaults() {
        mSet |= SET_SYNC_SOURCE | SET_AUDIO_ADJUST_MODE | SET_TOLERANCE;
        return this;
    }

    /**
     * Sets the audio adjust mode.
     * @param audioAdjustMode
     * @return this <code>SyncParams</code> instance.
     */
    public SyncParams 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>SyncParams</code> instance.
     */
    public SyncParams 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 platform specific, but is never more than 1/24.
     * @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>SyncParams</code> instance.
     * @throws IllegalArgumentException if the tolerance is negative, or not less than one.
     */
    public SyncParams setTolerance(float tolerance) {
        if (tolerance < 0.f || tolerance >= 1.f) {
            throw new IllegalArgumentException("tolerance must be less than one and non-negative");
        }
        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. A negative
     *     number is used to clear a previous hint.
     * @return this <code>SyncParams</code> instance.
     */
    public SyncParams 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}), or a negative
     *     number representing the desire to clear a previous hint using these params.
     * @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;
    }

}