MediaSync.java revision 7f08763f4140822c30d0e18d4d3939488c8d26f8
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; 32071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport java.util.LinkedList; 33071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiaimport java.util.List; 34071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 35071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia/** 36071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * MediaSync class can be used to synchronously playback audio and video streams. 37071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * It can be used to play audio-only or video-only stream, too. 38071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 39071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p>MediaSync is generally used like this: 40071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <pre> 41071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * MediaSync sync = new MediaSync(); 42071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.configureSurface(surface); 43071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Surface inputSurface = sync.createInputSurface(); 44071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 45071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // MediaCodec videoDecoder = ...; 46071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * videoDecoder.configure(format, inputSurface, ...); 47071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 48ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia * sync.configureAudioTrack(audioTrack); 49071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.setCallback(new MediaSync.Callback() { 50ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia * {@literal @Override} 51071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * public void onReturnAudioBuffer(MediaSync sync, ByteBuffer audioBuffer, int bufferIndex) { 52071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 53071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 54161537c81664613c79a6397759aa9baa5db6dd64Wei Jia * }, null); 55071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // This needs to be done since sync is paused on creation. 56071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.setPlaybackRate(1.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE); 57071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 58071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * for (;;) { 59071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 60071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // send video frames to surface for rendering, e.g., call 61071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // videoDecoder.releaseOutputBuffer(videoOutputBufferIx, videoPresentationTimeNs); 62071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // More details are available as below. 63071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 64071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.queueAudio(audioByteBuffer, bufferIndex, size, audioPresentationTimeUs); // non-blocking. 65071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // The audioByteBuffer and bufferIndex will be returned via callback. 66071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // More details are available as below. 67071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 68071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ... 69071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 70071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.setPlaybackRate(0.0f, MediaSync.PLAYBACK_RATE_AUDIO_MODE_RESAMPLE); 71071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.release(); 72071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync = null; 73071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 74071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // The following code snippet illustrates how video/audio raw frames are created by 75071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // MediaCodec's, how they are fed to MediaSync and how they are returned by MediaSync. 76071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // This is the callback from MediaCodec. 77071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * onOutputBufferAvailable(MediaCodec codec, int bufferIndex, BufferInfo info) { 78071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 79071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * if (codec == videoDecoder) { 80071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // surface timestamp must contain media presentation time in nanoseconds. 81071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * codec.releaseOutputBuffer(bufferIndex, 1000 * info.presentationTime); 82071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } else { 83071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * ByteBuffer audioByteBuffer = codec.getOutputBuffer(bufferIndex); 84071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * sync.queueByteBuffer(audioByteBuffer, bufferIndex, info.size, info.presentationTime); 85071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 86071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 87071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 88071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 89071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // This is the callback from MediaSync. 90071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * onReturnAudioBuffer(MediaSync sync, ByteBuffer buffer, int bufferIndex) { 91071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 92071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * audioDecoder.releaseBuffer(bufferIndex, false); 93071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * // ... 94071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * } 95071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 96071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * </pre> 97071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 98071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * The client needs to configure corresponding sink (i.e., Surface and AudioTrack) based on 99071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * the stream type it will play. 100071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 101071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * For video, the client needs to call {@link #createInputSurface} to obtain a surface on 102071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * which it will render video frames. 103071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 104071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * For audio, the client needs to set up audio track correctly, e.g., using {@link 105071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * AudioTrack#MODE_STREAM}. The audio buffers are sent to MediaSync directly via {@link 106071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * #queueAudio}, and are returned to the client via {@link Callback#onReturnAudioBuffer} 107071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * asynchronously. The client should not modify an audio buffer till it's returned. 108071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 109071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * The client can optionally pre-fill audio/video buffers by setting playback rate to 0.0, 110071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * and then feed audio/video buffers to corresponding components. This can reduce possible 111071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * initial underrun. 112071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 113071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 114071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jiafinal public class MediaSync { 115071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 116071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * MediaSync callback interface. Used to notify the user asynchronously 117071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * of various MediaSync events. 118071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 119071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public static abstract class Callback { 120071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 121071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Called when returning an audio buffer which has been consumed. 122071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 123071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param sync The MediaSync object. 124071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param audioBuffer The returned audio buffer. 12599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * @param bufferIndex The index associated with the audio buffer 126071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 127071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public abstract void onReturnAudioBuffer( 12899f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @NonNull MediaSync sync, @NonNull ByteBuffer audioBuffer, int bufferIndex); 129071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 130071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 131071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final String TAG = "MediaSync"; 132071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 133071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final int EVENT_CALLBACK = 1; 134071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final int EVENT_SET_CALLBACK = 2; 135071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 136071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static final int CB_RETURN_AUDIO_BUFFER = 1; 137071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 138071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static class AudioBuffer { 139071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public ByteBuffer mByteBuffer; 140071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public int mBufferIndex; 141071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public int mSizeInBytes; 142071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia long mPresentationTimeUs; 143071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 14499f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public AudioBuffer(@NonNull ByteBuffer byteBuffer, int bufferIndex, 145071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia int sizeInBytes, long presentationTimeUs) { 146071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mByteBuffer = byteBuffer; 147071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mBufferIndex = bufferIndex; 148071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mSizeInBytes = sizeInBytes; 149071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mPresentationTimeUs = presentationTimeUs; 150071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 151071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 152071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 153071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private final Object mCallbackLock = new Object(); 154071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Handler mCallbackHandler = null; 155071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private MediaSync.Callback mCallback = null; 156071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 157071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Thread mAudioThread = null; 158071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // Created on mAudioThread when mAudioThread is started. When used on user thread, they should 159071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // be guarded by checking mAudioThread. 160071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Handler mAudioHandler = null; 161071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private Looper mAudioLooper = null; 162071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 163071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private final Object mAudioLock = new Object(); 164071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private AudioTrack mAudioTrack = null; 165071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private List<AudioBuffer> mAudioBuffers = new LinkedList<AudioBuffer>(); 166071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private float mPlaybackRate = 0.0f; 167071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 168071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private long mNativeContext; 169071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 170071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 171071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Class constructor. On creation, MediaSync is paused, i.e., playback rate is 0.0f. 172071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 173071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public MediaSync() { 174071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_setup(); 175071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 176071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 177071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_setup(); 178071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 179071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @Override 180071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia protected void finalize() { 181071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_finalize(); 182071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 183071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 184071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_finalize(); 185071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 186071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 187071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Make sure you call this when you're done to free up any opened 188071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * component instance instead of relying on the garbage collector 189071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * to do this for you at some point in the future. 190071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 191071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public final void release() { 192071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia returnAudioBuffers(); 193071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioThread != null) { 194071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioLooper != null) { 195071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLooper.quit(); 196071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 197071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 198071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia setCallback(null, null); 199071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_release(); 200071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 201071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 202071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_release(); 203071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 204071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 205071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Sets an asynchronous callback for actionable MediaSync events. 20699f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * <p> 20799f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * This method can be called multiple times to update a previously set callback. If the 20899f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * handler is changed, undelivered notifications scheduled for the old handler may be dropped. 20999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * <p> 21099f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * <b>Do not call this inside callback.</b> 211071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 21299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * @param cb The callback that will run. Use {@code null} to stop receiving callbacks. 21399f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar * @param handler The Handler that will run the callback. Use {@code null} to use MediaSync's 214071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * internal handler if it exists. 215071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 21699f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public void setCallback(@Nullable /* MediaSync. */ Callback cb, @Nullable Handler handler) { 217071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mCallbackLock) { 218071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (handler != null) { 219071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler = handler; 220071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } else { 221071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia Looper looper; 222071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if ((looper = Looper.myLooper()) == null) { 223071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia looper = Looper.getMainLooper(); 224071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 225071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (looper == null) { 226071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler = null; 227071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } else { 228071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler = new Handler(looper); 229071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 230071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 231071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 232071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallback = cb; 233071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 234071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 235071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 236071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 237071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Configures the output surface for MediaSync. 238071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 239071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param surface Specify a surface on which to render the video data. 240071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalArgumentException if the surface has been released, or is invalid. 241071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * or can not be connected. 242071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if not in the Initialized state, or another surface 243071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * has already been configured. 244071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 24599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public void configureSurface(@Nullable Surface surface) { 246071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_configureSurface(surface); 247071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 248071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 24999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private native final void native_configureSurface(@Nullable Surface surface); 250071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 251071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 252071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Configures the audio track for MediaSync. 253071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 254071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param audioTrack Specify an AudioTrack through which to render the audio data. 255ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia * @throws IllegalArgumentException if the audioTrack has been released, or is invalid. 256071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if not in the Initialized state, or another audio track 257071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * has already been configured. 258071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 25999f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar public void configureAudioTrack(@Nullable AudioTrack audioTrack) { 260ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia // AudioTrack has sanity check for configured sample rate. 261ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia int nativeSampleRateInHz = (audioTrack == null ? 0 : audioTrack.getSampleRate()); 262ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia 263071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_configureAudioTrack(audioTrack, nativeSampleRateInHz); 264071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioTrack = audioTrack; 265ba5997e574c2f5cd794652abce40c19d02d5febfWei Jia if (audioTrack != null && mAudioThread == null) { 266071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia createAudioThread(); 267071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 268071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 269071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 270071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_configureAudioTrack( 27199f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @Nullable AudioTrack audioTrack, int nativeSampleRateInHz); 272071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 273071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 274071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Requests a Surface to use as the input. This may only be called after 275071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * {@link #configureSurface}. 276071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * <p> 277071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * The application is responsible for calling release() on the Surface when 278071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * done. 279071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if not configured, or another input surface has 280071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * already been created. 281071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 28299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @NonNull 283071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public native final Surface createInputSurface(); 284071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 285071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 286b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Resample audio data when changing playback speed. 287b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 288b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Resample the waveform based on the requested playback rate to get 289071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * a new waveform, and play back the new waveform at the original sampling 290071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * frequency. 291b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p><ul> 292b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <li>When rate is larger than 1.0, pitch becomes higher. 293b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <li>When rate is smaller than 1.0, pitch becomes lower. 294b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * </ul> 295071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 296b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public static final int PLAYBACK_RATE_AUDIO_MODE_RESAMPLE = 2; 297071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 298071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 299b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Time stretch audio when changing playback speed. 300b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 301071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Time stretching changes the duration of the audio samples without 302b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * affecting their pitch. This is only supported for a limited range 303b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * of playback speeds, e.g. from 1/2x to 2x. If the rate is adjusted 304b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * beyond this limit, the rate change will fail. 305071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 306071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public static final int PLAYBACK_RATE_AUDIO_MODE_STRETCH = 1; 307071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 308b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar /** 309b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Time stretch audio when changing playback speed, and may mute if 310b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * stretching is no longer supported. 311b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 312b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Time stretching changes the duration of the audio samples without 313b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * affecting their pitch. This is only supported for a limited range 314b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * of playback speeds, e.g. from 1/2x to 2x. When it is no longer 315b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * supported, the audio may be muted. Using this mode will not fail 316b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * for non-negative playback rates. 317b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar */ 318b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public static final int PLAYBACK_RATE_AUDIO_MODE_DEFAULT = 0; 319b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar 320071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** @hide */ 321071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @IntDef( 322071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia value = { 323b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PLAYBACK_RATE_AUDIO_MODE_DEFAULT, 324b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PLAYBACK_RATE_AUDIO_MODE_STRETCH, 325071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia PLAYBACK_RATE_AUDIO_MODE_RESAMPLE, 326b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar }) 327071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @Retention(RetentionPolicy.SOURCE) 328071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public @interface PlaybackRateAudioMode {} 329071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 330071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 331b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Sets playback rate and audio mode. 332071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 333071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param rate the ratio between desired playback rate and normal one. 1.0 means normal 334b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * playback speed. 0.0 means pause. Value larger than 1.0 means faster playback, 335b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate 336b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * does not change as a result of this call. To restore the original rate at any time, 337b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * use 1.0. 338b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @param audioMode audio playback mode. Must be one of the supported 339b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * audio modes. 340071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 341071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if the internal sync engine or the audio track has not 342071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * been initialized. 343b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @throws IllegalArgumentException if audioMode is not supported. 344071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 345b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public void setPlaybackRate(float rate, @PlaybackRateAudioMode int audioMode) { 346b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PlaybackSettings rateSettings = new PlaybackSettings(); 347b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.allowDefaults(); 348b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar switch (audioMode) { 349b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar case PLAYBACK_RATE_AUDIO_MODE_DEFAULT: 350b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.setSpeed(rate).setPitch(1.0f); 351b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar break; 352b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar case PLAYBACK_RATE_AUDIO_MODE_STRETCH: 353b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.setSpeed(rate).setPitch(1.0f) 354b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar .setAudioFallbackMode(rateSettings.AUDIO_FALLBACK_MODE_FAIL); 355b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar break; 356b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar case PLAYBACK_RATE_AUDIO_MODE_RESAMPLE: 357b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rateSettings.setSpeed(rate).setPitch(rate); 358b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar break; 359b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar default: 360b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar { 361b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar final String msg = "Audio playback mode " + audioMode + " is not supported"; 362b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar throw new IllegalArgumentException(msg); 363b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 364b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 365b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar setPlaybackSettings(rateSettings); 366071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 367071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 368071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 369b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Sets playback rate using {@link PlaybackSettings}. 370b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 371b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * When using MediaSync with {@link AudioTrack}, set playback settings using this 372b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * call instead of calling it directly on the track, so that the sync is aware of 373b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * the settings change. 374b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * <p> 375b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * This call also works if there is no audio track. 376071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 377b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @param settings the playback settings to use. {@link PlaybackSettings#getSpeed 378b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Speed} is the ratio between desired playback rate and normal one. 1.0 means 379b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * normal playback speed. 0.0 means pause. Value larger than 1.0 means faster playback, 380b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * while value between 0.0 and 1.0 for slower playback. <b>Note:</b> the normal rate 381b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * does not change as a result of this call. To restore the original rate at any time, 382b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * use speed of 1.0. 383071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * 384071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if the internal sync engine or the audio track has not 385071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * been initialized. 386b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @throws IllegalArgumentException if the settings are not supported. 387071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 388b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public void setPlaybackSettings(@NonNull PlaybackSettings settings) { 389b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar float rate; 390b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar try { 391b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar rate = settings.getSpeed(); 392b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar 393b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar // rate is specified 394b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mAudioTrack != null) { 395b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar try { 396b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (rate == 0.0) { 397b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.pause(); 398b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } else { 399b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.setPlaybackSettings(settings); 400b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.play(); 401b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 402b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } catch (IllegalStateException e) { 403b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar throw e; 404071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 405071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 406071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 407b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar synchronized(mAudioLock) { 408b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mPlaybackRate = rate; 409b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 410b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mPlaybackRate != 0.0 && mAudioThread != null) { 411b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar postRenderAudio(0); 412b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 413b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar native_setPlaybackRate(mPlaybackRate); 414b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } catch (IllegalStateException e) { 415b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar // rate is not specified; still, propagate settings to audio track 416b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mAudioTrack != null) { 417b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar mAudioTrack.setPlaybackSettings(settings); 418b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 419071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 420b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } 421071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 422b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar /** 423b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * Gets the playback rate using {@link PlaybackSettings}. 424b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * 425b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @return the playback rate being used. 426b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * 427b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * @throws IllegalStateException if the internal sync engine or the audio track has not 428b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar * been initialized. 429b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar */ 430b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar @NonNull 431b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar public PlaybackSettings getPlaybackSettings() { 432b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar if (mAudioTrack != null) { 433b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar return mAudioTrack.getPlaybackSettings(); 434b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar } else { 435b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar PlaybackSettings settings = new PlaybackSettings(); 436b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar settings.allowDefaults(); 437b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar settings.setSpeed(mPlaybackRate); 438b3d5fd252851071f2f7e3dd66be84683750379abLajos Molnar return settings; 439071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 440071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 441071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 442071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_setPlaybackRate(float rate); 443071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 444c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar /** 445c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * Sets A/V sync mode. 446c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 447c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @param settings the A/V sync settings to apply 448c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 449c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalStateException if the internal player engine has not been 450c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * initialized. 451c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalArgumentException if settings are not supported. 452c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar */ 453c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar public native void setSyncSettings(@NonNull SyncSettings settings); 454c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar 455c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar /** 456c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * Gets the A/V sync mode. 457c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 458c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @return the A/V sync settings 459c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 460c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalStateException if the internal player engine has not been 461c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * initialized. 462c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar */ 463c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar @NonNull 464c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar public native SyncSettings getSyncSettings(); 465c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar 466c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar /** 467c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * Flushes all buffers from the sync object. 468c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * <p> 469c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * No callbacks are received for the flushed buffers. 470c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * 471c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * @throws IllegalStateException if the internal player engine has not been 472c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar * initialized. 473c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar */ 474c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar public void flush() { 475c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar synchronized(mAudioLock) { 476c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar mAudioBuffers.clear(); 477c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar mCallbackHandler.removeCallbacksAndMessages(null); 478c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar } 479c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar // TODO implement this for surface buffers. 480c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar } 481c98f58efd147c574faa4a4f9956b5ab95e3027a5Lajos Molnar 482217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia /** 483217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * Get current playback position. 484217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * <p> 4857f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * The MediaTimestamp represents how the media time correlates to the system time in 4867f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * a linear fashion. It contains the media time and system timestamp of an anchor frame 4877f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * ({@link MediaTimestamp#mediaTimeUs} and {@link MediaTimestamp#nanoTime}) 4887f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * and the speed of the media clock ({@link MediaTimestamp#clockRate}). 4897f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * <p> 4907f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * During regular playback, the media time moves fairly constantly (though the 4917f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * anchor frame may be rebased to a current system time, the linear correlation stays 4927f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * steady). Therefore, this method does not need to be called often. 493217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * <p> 494217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * To help users to get current playback position, this method always returns the timestamp of 495217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * just-rendered frame, i.e., {@link System#nanoTime} and its corresponding media time. They 496217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * can be used as current playback position. 497217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia * 4987f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * @return a MediaTimestamp object if a timestamp is available, or {@code null} if no timestamp 4997f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar * is available, e.g. because the media sync has not been initialized. 500217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia */ 5017f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar @Nullable 5027f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar public MediaTimestamp getTimestamp() 503217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia { 5047f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar try { 5057f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar // TODO: create the timestamp in native 5067f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar MediaTimestamp timestamp = new MediaTimestamp(); 5077f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar if (native_getTimestamp(timestamp)) { 5087f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar return timestamp; 5097f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar } else { 5107f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar return null; 5117f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar } 5127f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar } catch (IllegalStateException e) { 5137f08763f4140822c30d0e18d4d3939488c8d26f8Lajos Molnar return null; 514217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia } 515217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia } 516217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia 51799f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private native final boolean native_getTimestamp(@NonNull MediaTimestamp timestamp); 518217ec0adfc35302a6cc6b04bc78bf8fd82ffc8a5Wei Jia 519071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia /** 520071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * Queues the audio data asynchronously for playback (AudioTrack must be in streaming mode). 521071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param audioData the buffer that holds the data to play. This buffer will be returned 522071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * to the client via registered callback. 523071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param bufferIndex the buffer index used to identify audioData. It will be returned to 524071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * the client along with audioData. This helps applications to keep track of audioData. 525071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param sizeInBytes number of bytes to queue. 526071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @param presentationTimeUs the presentation timestamp in microseconds for the first frame 527071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * in the buffer. 528071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * @throws IllegalStateException if audio track is not configured or internal configureation 529071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia * has not been done correctly. 530071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia */ 531071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void queueAudio( 53299f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar @NonNull ByteBuffer audioData, int bufferIndex, int sizeInBytes, 53399f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar long presentationTimeUs) { 534071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioTrack == null || mAudioThread == null) { 535071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia throw new IllegalStateException( 536071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia "AudioTrack is NOT configured or audio thread is not created"); 537071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 538071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 539071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 540071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioBuffers.add(new AudioBuffer( 541071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioData, bufferIndex, sizeInBytes, presentationTimeUs)); 542071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 543071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 544071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mPlaybackRate != 0.0) { 545071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postRenderAudio(0); 546071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 547071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 548071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 549071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // When called on user thread, make sure to check mAudioThread != null. 550071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private void postRenderAudio(long delayMillis) { 551071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioHandler.postDelayed(new Runnable() { 552071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void run() { 553071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 554071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mPlaybackRate == 0.0) { 555071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 556071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 557071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 558071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mAudioBuffers.isEmpty()) { 559071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 560071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 561071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 562071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia AudioBuffer audioBuffer = mAudioBuffers.get(0); 563071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia int sizeWritten = mAudioTrack.write( 564071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mByteBuffer, 565071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mSizeInBytes, 566071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia AudioTrack.WRITE_NON_BLOCKING); 567071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (sizeWritten > 0) { 568071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (audioBuffer.mPresentationTimeUs != -1) { 569071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_updateQueuedAudioData( 570071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mSizeInBytes, audioBuffer.mPresentationTimeUs); 571071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mPresentationTimeUs = -1; 572071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 573071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 574071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (sizeWritten == audioBuffer.mSizeInBytes) { 575071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postReturnByteBuffer(audioBuffer); 576071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioBuffers.remove(0); 577071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (!mAudioBuffers.isEmpty()) { 578071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postRenderAudio(0); 579071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 580071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 581071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 582071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 583071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mSizeInBytes -= sizeWritten; 584071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 585071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // TODO: wait time depends on fullness of audio track. 586071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postRenderAudio(10); 587071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 588071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 589071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia }, delayMillis); 590071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 591071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 592071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private native final void native_updateQueuedAudioData( 593071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia int sizeInBytes, long presentationTimeUs); 594071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 59599f8072386ce9891a5973d591dc1a30e45b50bc6Lajos Molnar private final void postReturnByteBuffer(@NonNull final AudioBuffer audioBuffer) { 596071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mCallbackLock) { 597071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mCallbackHandler != null) { 598071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia final MediaSync sync = this; 599071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallbackHandler.post(new Runnable() { 600071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void run() { 601071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mCallbackLock) { 602071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mCallbackHandler == null 603071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia || mCallbackHandler.getLooper().getThread() 604071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia != Thread.currentThread()) { 605071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia // callback handler has been changed. 606071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia return; 607071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 608071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia if (mCallback != null) { 609071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mCallback.onReturnAudioBuffer(sync, audioBuffer.mByteBuffer, 610071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia audioBuffer.mBufferIndex); 611071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 612071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 613071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 614071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia }); 615071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 616071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 617071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 618071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 619071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private final void returnAudioBuffers() { 620071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 621071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia for (AudioBuffer audioBuffer: mAudioBuffers) { 622071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia postReturnByteBuffer(audioBuffer); 623071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 624071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioBuffers.clear(); 625071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 626071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 627071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 628071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private void createAudioThread() { 629071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioThread = new Thread() { 630071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia @Override 631071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia public void run() { 632071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia Looper.prepare(); 633071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 634071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLooper = Looper.myLooper(); 635071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioHandler = new Handler(); 636071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLock.notify(); 637071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 638071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia Looper.loop(); 639071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 640071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia }; 641071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioThread.start(); 642071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 643071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia synchronized(mAudioLock) { 644071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia try { 645071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia mAudioLock.wait(); 646071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } catch(InterruptedException e) { 647071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 648071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 649071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 650071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 651071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia static { 652071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia System.loadLibrary("media_jni"); 653071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia native_init(); 654071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia } 655071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia 656071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia private static native final void native_init(); 657071a8b71d1212e218a3ebf7dbb8908a4acf5cf6dWei Jia} 658