MediaSync.java revision 25b802d47249702b9e5d175b3e7144934b67553d
1071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia/* 2071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Copyright (C) 2015 The Android Open Source Project 3071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 4071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Licensed under the Apache License, Version 2.0 (the "License"); 5071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * you may not use this file except in compliance with the License. 6071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * You may obtain a copy of the License at 7071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 8071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * http://www.apache.org/licenses/LICENSE-2.0 9071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 10071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Unless required by applicable law or agreed to in writing, software 11071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * distributed under the License is distributed on an "AS IS" BASIS, 12071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * See the License for the specific language governing permissions and 14071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * limitations under the License. 15071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 16071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 17071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiapackage android.media; 18071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 19071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport android.annotation.IntDef; 20217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jiaimport android.annotation.NonNull; 2199f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnarimport android.annotation.Nullable; 22071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport android.media.AudioTrack; 23b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnarimport android.media.PlaybackSettings; 24071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport android.os.Handler; 25071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport android.os.Looper; 26071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport android.os.Message; 27071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport android.view.Surface; 28071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 29071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport java.lang.annotation.Retention; 30071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport java.lang.annotation.RetentionPolicy; 31071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport java.nio.ByteBuffer; 3225b802d47249702b9e5d175b3e7144934b67553dWei Jiaimport java.util.concurrent.TimeUnit; 33071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport java.util.LinkedList; 34071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport java.util.List; 35071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 36071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia/** 37071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * MediaSync class can be used to synchronously playback audio and video streams. 38071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * It can be used to play audio-only or video-only stream, too. 39071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 40071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p>MediaSync is generally used like this: 41071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <pre> 42071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * MediaSync sync = new MediaSync(); 43aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * sync.setSurface(surface); 44071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Surface inputSurface = sync.createInputSurface(); 45071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 46071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // MediaCodec videoDecoder = ...; 47071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * videoDecoder.configure(format, inputSurface, ...); 48071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 49aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * sync.setAudioTrack(audioTrack); 50071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.setCallback(new MediaSync.Callback() { 51ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia * {@literal @Override} 52071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * public void onReturnAudioBuffer(MediaSync sync, ByteBuffer audioBuffer, int bufferIndex) { 53071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 54071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 55161537c81664613c79a6397759aa9baa5db6dd64Wei Jia * }, null); 56071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // This needs to be done since sync is paused on creation. 57071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.setPlaybackRate(1.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE); 58071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 59071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * for (;;) { 60071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 61071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // send video frames to surface for rendering, e.g., call 62071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // videoDecoder.releaseOutputBuffer(videoOutputBufferIx, videoPresentationTimeNs); 63071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // More details are available as below. 64071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 65071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.queueAudio(audioByteBuffer, bufferIndex, size, audioPresentationTimeUs); // non-blocking. 66071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // The audioByteBuffer and bufferIndex will be returned via callback. 67071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // More details are available as below. 68071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 69071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 70071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 71071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.setPlaybackRate(0.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE); 72071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.release(); 73071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync = null; 74071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 75071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // The following code snippet illustrates how video/audio raw frames are created by 76071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // MediaCodec's, how they are fed to MediaSync and how they are returned by MediaSync. 77071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // This is the callback from MediaCodec. 78071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * onOutputBufferAvailable(MediaCodec codec, int bufferIndex, BufferInfo info) { 79071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 80071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * if (codec == videoDecoder) { 81071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // surface timestamp must contain media presentation time in nanoseconds. 82071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * codec.releaseOutputBuffer(bufferIndex, 1000 * info.presentationTime); 83071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } else { 84071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ByteBuffer audioByteBuffer = codec.getOutputBuffer(bufferIndex); 85071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.queueByteBuffer(audioByteBuffer, bufferIndex, info.size, info.presentationTime); 86071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 87071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 88071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 89071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 90071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // This is the callback from MediaSync. 91071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * onReturnAudioBuffer(MediaSync sync, ByteBuffer buffer, int bufferIndex) { 92071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 93071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * audioDecoder.releaseBuffer(bufferIndex, false); 94071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 95071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 96071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 97071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * </pre> 98071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 99aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * The client needs to configure corresponding sink by setting the Surface and/or AudioTrack 100aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * based on the stream type it will play. 101071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 102071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * For video, the client needs to call {@link #createInputSurface} to obtain a surface on 103071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * which it will render video frames. 104071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 105071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * For audio, the client needs to set up audio track correctly, e.g., using {@link 106071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * AudioTrack#MODE_STREAM}. The audio buffers are sent to MediaSync directly via {@link 107071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * #queueAudio}, and are returned to the client via {@link Callback#onReturnAudioBuffer} 108071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * asynchronously. The client should not modify an audio buffer till it's returned. 109071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 110071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * The client can optionally pre-fill audio/video buffers by setting playback rate to 0.0, 111071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * and then feed audio/video buffers to corresponding components. This can reduce possible 112071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * initial underrun. 113071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 114071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 115071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiafinal public class MediaSync { 116071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 117071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * MediaSync callback interface. Used to notify the user asynchronously 118071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * of various MediaSync events. 119071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 120071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public static abstract class Callback { 121071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 122071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Called when returning an audio buffer which has been consumed. 123071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 124071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param sync The MediaSync object. 125071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param audioBuffer The returned audio buffer. 12699f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * @param bufferIndex The index associated with the audio buffer 127071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 128071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public abstract void onReturnAudioBuffer( 12999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @NonNull MediaSync sync, @NonNull ByteBuffer audioBuffer, int bufferIndex); 130071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 131071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 132071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final String TAG = "MediaSync"; 133071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 134071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final int EVENT_CALLBACK = 1; 135071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final int EVENT_SET_CALLBACK = 2; 136071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 137071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final int CB_RETURN_AUDIO_BUFFER = 1; 138071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 139071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static class AudioBuffer { 140071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public ByteBuffer mByteBuffer; 141071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public int mBufferIndex; 142071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public int mSizeInBytes; 143071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia long mPresentationTimeUs; 144071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 14599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public AudioBuffer(@NonNull ByteBuffer byteBuffer, int bufferIndex, 146071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia int sizeInBytes, long presentationTimeUs) { 147071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mByteBuffer = byteBuffer; 148071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mBufferIndex = bufferIndex; 149071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mSizeInBytes = sizeInBytes; 150071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mPresentationTimeUs = presentationTimeUs; 151071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 152071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 153071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 154071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private final Object mCallbackLock = new Object(); 155071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Handler mCallbackHandler = null; 156071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private MediaSync.Callback mCallback = null; 157071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 158071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Thread mAudioThread = null; 159071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // Created on mAudioThread when mAudioThread is started. When used on user thread, they should 160071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // be guarded by checking mAudioThread. 161071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Handler mAudioHandler = null; 162071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Looper mAudioLooper = null; 163071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 164071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private final Object mAudioLock = new Object(); 165071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private AudioTrack mAudioTrack = null; 166071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private List<AudioBuffer> mAudioBuffers = new LinkedList<AudioBuffer>(); 167071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private float mPlaybackRate = 0.0f; 168071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 169071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private long mNativeContext; 170071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 171071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 172071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Class constructor. On creation, MediaSync is paused, i.e., playback rate is 0.0f. 173071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 174071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public MediaSync() { 175071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_setup(); 176071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 177071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 178071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_setup(); 179071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 180071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @Override 181071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia protected void finalize() { 182071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_finalize(); 183071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 184071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 185071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_finalize(); 186071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 187071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 188071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Make sure you call this when you're done to free up any opened 189071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * component instance instead of relying on the garbage collector 190071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * to do this for you at some point in the future. 191071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 192071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public final void release() { 193071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia returnAudioBuffers(); 194071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioThread != null) { 195071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioLooper != null) { 196071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLooper.quit(); 197071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 198071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 199071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia setCallback(null, null); 200071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_release(); 201071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 202071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 203071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_release(); 204071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 205071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 206071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Sets an asynchronous callback for actionable MediaSync events. 20799f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * <p> 20899f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * This method can be called multiple times to update a previously set callback. If the 20999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * handler is changed, undelivered notifications scheduled for the old handler may be dropped. 21099f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * <p> 21199f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * <b>Do not call this inside callback.</b> 212071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 21399f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * @param cb The callback that will run. Use {@code null} to stop receiving callbacks. 21499f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * @param handler The Handler that will run the callback. Use {@code null} to use MediaSync's 215071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * internal handler if it exists. 216071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 21799f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public void setCallback(@Nullable /* MediaSync. */ Callback cb, @Nullable Handler handler) { 218071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mCallbackLock) { 219071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (handler != null) { 220071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler = handler; 221071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } else { 222071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia Looper looper; 223071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if ((looper = Looper.myLooper()) == null) { 224071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia looper = Looper.getMainLooper(); 225071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 226071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (looper == null) { 227071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler = null; 228071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } else { 229071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler = new Handler(looper); 230071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 231071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 232071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 233071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallback = cb; 234071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 235071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 236071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 237071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 238aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * Sets the output surface for MediaSync. 239aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * <p> 240aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * Currently, this is only supported in the Initialized state. 241071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 242071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param surface Specify a surface on which to render the video data. 243aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * @throws IllegalArgumentException if the surface has been released, is invalid, 244071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * or can not be connected. 245aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * @throws IllegalStateException if setting the surface is not supported, e.g. 246aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * not in the Initialized state, or another surface has already been configured. 247071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 248aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar public void setSurface(@Nullable Surface surface) { 249071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_configureSurface(surface); 250071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 251071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 25299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private native final void native_configureSurface(@Nullable Surface surface); 253071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 254071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 255aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * Sets the audio track for MediaSync. 256aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * <p> 257aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * Currently, this is only supported in the Initialized state. 258071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 259071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param audioTrack Specify an AudioTrack through which to render the audio data. 260ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia * @throws IllegalArgumentException if the audioTrack has been released, or is invalid. 261aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * @throws IllegalStateException if setting the audio track is not supported, e.g. 262aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * not in the Initialized state, or another audio track has already been configured. 263071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 264aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar public void setAudioTrack(@Nullable AudioTrack audioTrack) { 265ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia // AudioTrack has sanity check for configured sample rate. 266ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia int nativeSampleRateInHz = (audioTrack == null ? 0 : audioTrack.getSampleRate()); 267ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia 268071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_configureAudioTrack(audioTrack, nativeSampleRateInHz); 269071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioTrack = audioTrack; 270ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia if (audioTrack != null && mAudioThread == null) { 271071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia createAudioThread(); 272071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 273071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 274071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 275071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_configureAudioTrack( 27699f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @Nullable AudioTrack audioTrack, int nativeSampleRateInHz); 277071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 278071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 279071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Requests a Surface to use as the input. This may only be called after 280aba29b77a5742fc920ec62dbc9ddb6f025759d65Lajos Molnar * {@link #setSurface}. 281071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 282071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * The application is responsible for calling release() on the Surface when 283071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * done. 284071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if not configured, or another input surface has 285071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * already been created. 286071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 28799f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @NonNull 288071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public native final Surface createInputSurface(); 289071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 290071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 291b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Resample audio data when changing playback speed. 292b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 293b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Resample the waveform based on the requested playback rate to get 294071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * a new waveform, and play back the new waveform at the original sampling 295071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * frequency. 296b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p><ul> 297b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <li>When rate is larger than 1.0, pitch becomes higher. 298b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <li>When rate is smaller than 1.0, pitch becomes lower. 299b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * </ul> 300071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 301b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; 302071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 303071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 304b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Time stretch audio when changing playback speed. 305b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 306071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Time stretching changes the duration of the audio samples without 307b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * affecting their pitch. This is only supported for a limited range 308b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * of playback speeds, e.g. from 1/2x to 2x. If the rate is adjusted 309b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * beyond this limit, the rate change will fail. 310071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 311071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; 312071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 313b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar /** 314b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Time stretch audio when changing playback speed, and may mute if 315b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * stretching is no longer supported. 316b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 317b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Time stretching changes the duration of the audio samples without 318b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * affecting their pitch. This is only supported for a limited range 319b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * of playback speeds, e.g. from 1/2x to 2x. When it is no longer 320b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * supported, the audio may be muted. Using this mode will not fail 321b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * for non-negative playback rates. 322b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar */ 323b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; 324b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar 325071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** @hide */ 326071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @IntDef( 327071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia value = { 328b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PLAYBACK_RATE_AUDIO_MODE_DEFAULT, 329b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PLAYBACK_RATE_AUDIO_MODE_STRETCH, 330071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia PLAYBACK_RATE_AUDIO_MODE_RESAMPLE, 331b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar }) 332071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @Retention(RetentionPolicy.SOURCE) 333071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public @interface PlaybackRateAudioMode {} 334071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 335071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 336b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Sets playback rate and audio mode. 337071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 338071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param rate the ratio between desired playback rate and normal one. 1.0 means normal 339b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * playback speed. 0.0 means pause. Value larger than 1.0 means faster playback, 340b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate 341b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * does not change as a result of this call. To restore the original rate at any time, 342b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * use 1.0. 343b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @param audioMode audio playback mode. Must be one of the supported 344b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * audio modes. 345071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 346071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if the internal sync engine or the audio track has not 347071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * been initialized. 348b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @throws IllegalArgumentException if audioMode is not supported. 349071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 350b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) { 351b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PlaybackSettings rateSettings = new PlaybackSettings(); 352b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.allowDefaults(); 353b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar switch (audioMode) { 354b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar case PLAYBACK_RATE_AUDIO_MODE_DEFAULT: 355b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.setSpeed(rate).setPitch(1.0f); 356b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar break; 357b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar case PLAYBACK_RATE_AUDIO_MODE_STRETCH: 358b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.setSpeed(rate).setPitch(1.0f) 359b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar .setAudioFallbackMode(rateSettings.AUDIO_FALLBACK_MODE_FAIL); 360b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar break; 361b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE: 362b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.setSpeed(rate).setPitch(rate); 363b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar break; 364b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar default: 365b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar { 366b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar final String msg = "Audio playback mode " + audioMode + " is not supported"; 367b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar throw new IllegalArgumentException(msg); 368b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 369b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 370b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar setPlaybackSettings(rateSettings); 371071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 372071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 373071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 374b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Sets playback rate using {@link PlaybackSettings}. 375b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 376b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * When using MediaSync with {@link AudioTrack}, set playback settings using this 377b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * call instead of calling it directly on the track, so that the sync is aware of 378b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * the settings change. 379b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 380b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * This call also works if there is no audio track. 381071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 382b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @param settings the playback settings to use. {@link PlaybackSettings#getSpeed 383b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Speed} is the ratio between desired playback rate and normal one. 1.0 means 384b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * normal playback speed. 0.0 means pause. Value larger than 1.0 means faster playback, 385b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate 386b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * does not change as a result of this call. To restore the original rate at any time, 387b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * use speed of 1.0. 388071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 389071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if the internal sync engine or the audio track has not 390071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * been initialized. 391b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @throws IllegalArgumentException if the settings are not supported. 392071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 393b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public void setPlaybackSettings(@NonNull PlaybackSettings settings) { 394b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar float rate; 395b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar try { 396b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rate = settings.getSpeed(); 397b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar 398b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar // rate is specified 399b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mAudioTrack != null) { 400b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar try { 401b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (rate == 0.0) { 402b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.pause(); 403b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } else { 404b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.setPlaybackSettings(settings); 405b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.play(); 406b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 407b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } catch (IllegalStateException e) { 408b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar throw e; 409071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 410071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 411071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 412b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar synchronized(mAudioLock) { 413b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mPlaybackRate = rate; 414b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 415b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mPlaybackRate != 0.0 && mAudioThread != null) { 416b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar postRenderAudio(0); 417b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 418b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar native_setPlaybackRate(mPlaybackRate); 419b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } catch (IllegalStateException e) { 420b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar // rate is not specified; still, propagate settings to audio track 421b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mAudioTrack != null) { 422b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.setPlaybackSettings(settings); 423b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 424071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 425b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 426071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 427b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar /** 428b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Gets the playback rate using {@link PlaybackSettings}. 429b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * 430b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @return the playback rate being used. 431b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * 432b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @throws IllegalStateException if the internal sync engine or the audio track has not 433b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * been initialized. 434b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar */ 435b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar @NonNull 436b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public PlaybackSettings getPlaybackSettings() { 437b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mAudioTrack != null) { 438b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar return mAudioTrack.getPlaybackSettings(); 439b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } else { 440b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PlaybackSettings settings = new PlaybackSettings(); 441b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar settings.allowDefaults(); 442b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar settings.setSpeed(mPlaybackRate); 443b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar return settings; 444071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 445071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 446071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 447071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_setPlaybackRate(float rate); 448071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 449c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar /** 450c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * Sets A/V sync mode. 451c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 452c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @param settings the A/V sync settings to apply 453c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 454c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalStateException if the internal player engine has not been 455c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * initialized. 456c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalArgumentException if settings are not supported. 457c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar */ 458c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar public native void setSyncSettings(@NonNull SyncSettings settings); 459c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar 460c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar /** 461c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * Gets the A/V sync mode. 462c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 463c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @return the A/V sync settings 464c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 465c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalStateException if the internal player engine has not been 466c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * initialized. 467c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar */ 468c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar @NonNull 469c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar public native SyncSettings getSyncSettings(); 470c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar 471c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar /** 472c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * Flushes all buffers from the sync object. 473c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * <p> 474c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * No callbacks are received for the flushed buffers. 475c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 476c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalStateException if the internal player engine has not been 477c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * initialized. 478c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar */ 479c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar public void flush() { 480c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar synchronized(mAudioLock) { 481c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar mAudioBuffers.clear(); 482c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar mCallbackHandler.removeCallbacksAndMessages(null); 483c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar } 484c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar // TODO implement this for surface buffers. 485c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar } 486c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar 487217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia /** 488217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * Get current playback position. 489217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * <p> 4907f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * The MediaTimestamp represents how the media time correlates to the system time in 4917f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * a linear fashion. It contains the media time and system timestamp of an anchor frame 4927f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * ({@link MediaTimestamp#mediaTimeUs} and {@link MediaTimestamp#nanoTime}) 4937f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * and the speed of the media clock ({@link MediaTimestamp#clockRate}). 4947f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * <p> 4957f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * During regular playback, the media time moves fairly constantly (though the 4967f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * anchor frame may be rebased to a current system time, the linear correlation stays 4977f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * steady). Therefore, this method does not need to be called often. 498217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * <p> 499217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * To help users to get current playback position, this method always returns the timestamp of 500217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * just-rendered frame, i.e., {@link System#nanoTime} and its corresponding media time. They 501217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * can be used as current playback position. 502217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * 5037f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp 5047f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * is available, e.g. because the media sync has not been initialized. 505217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia */ 5067f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar @Nullable 5077f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar public MediaTimestamp getTimestamp() 508217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia { 5097f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar try { 5107f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar // TODO: create the timestamp in native 5117f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar MediaTimestamp timestamp = new MediaTimestamp(); 5127f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar if (native_getTimestamp(timestamp)) { 5137f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar return timestamp; 5147f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar } else { 5157f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar return null; 5167f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar } 5177f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar } catch (IllegalStateException e) { 5187f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar return null; 519217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia } 520217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia } 521217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia 52299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private native final boolean native_getTimestamp(@NonNull MediaTimestamp timestamp); 523217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia 524071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 525071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Queues the audio data asynchronously for playback (AudioTrack must be in streaming mode). 526071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param audioData the buffer that holds the data to play. This buffer will be returned 527071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * to the client via registered callback. 528071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param bufferIndex the buffer index used to identify audioData. It will be returned to 529071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * the client along with audioData. This helps applications to keep track of audioData. 530071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param sizeInBytes number of bytes to queue. 531071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param presentationTimeUs the presentation timestamp in microseconds for the first frame 532071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * in the buffer. 533071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if audio track is not configured or internal configureation 534071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * has not been done correctly. 535071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 536071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void queueAudio( 53799f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @NonNull ByteBuffer audioData, int bufferIndex, int sizeInBytes, 53899f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar long presentationTimeUs) { 539071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioTrack == null || mAudioThread == null) { 540071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia throw new IllegalStateException( 541071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia "AudioTrack is NOT configured or audio thread is not created"); 542071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 543071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 544071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 545071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioBuffers.add(new AudioBuffer( 546071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioData, bufferIndex, sizeInBytes, presentationTimeUs)); 547071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 548071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 549071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mPlaybackRate != 0.0) { 550071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postRenderAudio(0); 551071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 552071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 553071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 554071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // When called on user thread, make sure to check mAudioThread != null. 555071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private void postRenderAudio(long delayMillis) { 556071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioHandler.postDelayed(new Runnable() { 557071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void run() { 558071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 559071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mPlaybackRate == 0.0) { 560071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 561071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 562071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 563071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioBuffers.isEmpty()) { 564071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 565071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 566071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 567071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia AudioBuffer audioBuffer = mAudioBuffers.get(0); 568071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia int sizeWritten = mAudioTrack.write( 569071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mByteBuffer, 570071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mSizeInBytes, 571071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia AudioTrack.WRITE_NON_BLOCKING); 572071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (sizeWritten > 0) { 573071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (audioBuffer.mPresentationTimeUs != -1) { 574071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_updateQueuedAudioData( 575071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mSizeInBytes, audioBuffer.mPresentationTimeUs); 576071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mPresentationTimeUs = -1; 577071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 578071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 579071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (sizeWritten == audioBuffer.mSizeInBytes) { 580071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postReturnByteBuffer(audioBuffer); 581071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioBuffers.remove(0); 582071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (!mAudioBuffers.isEmpty()) { 583071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postRenderAudio(0); 584071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 585071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 586071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 587071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 588071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mSizeInBytes -= sizeWritten; 589071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 59025b802d47249702b9e5d175b3e7144934b67553dWei Jia long pendingTimeMs = TimeUnit.MICROSECONDS.toMillis( 59125b802d47249702b9e5d175b3e7144934b67553dWei Jia native_getPlayTimeForPendingAudioFrames()); 59225b802d47249702b9e5d175b3e7144934b67553dWei Jia postRenderAudio(pendingTimeMs / 2); 593071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 594071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 595071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia }, delayMillis); 596071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 597071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 598071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_updateQueuedAudioData( 599071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia int sizeInBytes, long presentationTimeUs); 600071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 60125b802d47249702b9e5d175b3e7144934b67553dWei Jia private native final long native_getPlayTimeForPendingAudioFrames(); 60225b802d47249702b9e5d175b3e7144934b67553dWei Jia 60399f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private final void postReturnByteBuffer(@NonNull final AudioBuffer audioBuffer) { 604071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mCallbackLock) { 605071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mCallbackHandler != null) { 606071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia final MediaSync sync = this; 607071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler.post(new Runnable() { 608071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void run() { 609071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mCallbackLock) { 610071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mCallbackHandler == null 611071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia || mCallbackHandler.getLooper().getThread() 612071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia != Thread.currentThread()) { 613071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // callback handler has been changed. 614071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 615071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 616071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mCallback != null) { 617071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallback.onReturnAudioBuffer(sync, audioBuffer.mByteBuffer, 618071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mBufferIndex); 619071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 620071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 621071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 622071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia }); 623071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 624071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 625071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 626071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 627071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private final void returnAudioBuffers() { 628071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 629071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia for (AudioBuffer audioBuffer: mAudioBuffers) { 630071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postReturnByteBuffer(audioBuffer); 631071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 632071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioBuffers.clear(); 633071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 634071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 635071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 636071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private void createAudioThread() { 637071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioThread = new Thread() { 638071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @Override 639071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void run() { 640071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia Looper.prepare(); 641071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 642071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLooper = Looper.myLooper(); 643071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioHandler = new Handler(); 644071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLock.notify(); 645071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 646071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia Looper.loop(); 647071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 648071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia }; 649071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioThread.start(); 650071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 651071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 652071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia try { 653071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLock.wait(); 654071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } catch(InterruptedException e) { 655071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 656071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 657071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 658071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 659071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia static { 660071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia System.loadLibrary("media_jni"); 661071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_init(); 662071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 663071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 664071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static native final void native_init(); 665071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia} 666