11abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/* 21abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Copyright (C) 2015 The Android Open Source Project 31abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 41abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Licensed under the Apache License, Version 2.0 (the "License"); 51abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * you may not use this file except in compliance with the License. 61abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * You may obtain a copy of the License at 71abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 81abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * http://www.apache.org/licenses/LICENSE-2.0 91abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * 101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * Unless required by applicable law or agreed to in writing, software 111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * distributed under the License is distributed on an "AS IS" BASIS, 121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * See the License for the specific language governing permissions and 141abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * limitations under the License. 151abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 176ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkopackage com.android.tv.tuner.exoplayer.audio; 181abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 191abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport android.media.MediaFormat; 201abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 216ebde20b03db4c0d57f67acaac11832b610b966bNick Chalkoimport com.google.android.exoplayer.C; 221abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport com.google.android.exoplayer.audio.AudioTrack; 231abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 241abddd9f6225298066094e20a6c29061b6af4590Nick Chalkoimport java.nio.ByteBuffer; 251abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 261abddd9f6225298066094e20a6c29061b6af4590Nick Chalko/** 271abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * {@link AudioTrack} wrapper class for trickplay operations including FF/RW. 281abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * FF/RW trickplay operations do not need framework {@link AudioTrack}. 291abddd9f6225298066094e20a6c29061b6af4590Nick Chalko * This wrapper class will do nothing in disabled status for those operations. 301abddd9f6225298066094e20a6c29061b6af4590Nick Chalko */ 311abddd9f6225298066094e20a6c29061b6af4590Nick Chalkopublic class AudioTrackWrapper { 326ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final int PCM16_FRAME_BYTES = 2; 336ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final int AC3_FRAMES_IN_ONE_SAMPLE = 1536; 346ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko private static final int BUFFERED_SAMPLES_IN_AUDIOTRACK = 356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko MpegTsDefaultAudioTrackRenderer.BUFFERED_SAMPLES_IN_AUDIOTRACK; 361abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private final AudioTrack mAudioTrack = new AudioTrack(); 371abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private int mAudioSessionID; 381abddd9f6225298066094e20a6c29061b6af4590Nick Chalko private boolean mIsEnabled; 391abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 401abddd9f6225298066094e20a6c29061b6af4590Nick Chalko AudioTrackWrapper() { 411abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mIsEnabled = true; 421abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void resetSessionId() { 451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioSessionID = AudioTrack.SESSION_ID_NOT_SET; 461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isInitialized() { 4965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return mIsEnabled && mAudioTrack.isInitialized(); 501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void restart() { 531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mAudioTrack.isInitialized()) { 541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.release(); 551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mIsEnabled = true; 571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko resetSessionId(); 581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void release() { 611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) { 621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.release(); 631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void initialize() throws AudioTrack.InitializationException { 671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mIsEnabled) { 681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) { 711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.initialize(mAudioSessionID); 721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } else { 731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioSessionID = mAudioTrack.initialize(); 741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 771abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void reset() { 781abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mIsEnabled) { 791abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 801abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 811abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.reset(); 821abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 831abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 841abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isEnded() { 8565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko return !mIsEnabled || !mAudioTrack.hasPendingData(); 861abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 871abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 881abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isReady() { 892e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko // In the case of not playing actual audio data, Audio track is always ready. 902e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko return !mIsEnabled || mAudioTrack.hasPendingData(); 911abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 921abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 931abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void play() { 941abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mIsEnabled) { 951abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 961abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 971abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.play(); 981abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 991abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1001abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void pause() { 1011abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mIsEnabled) { 1021abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 1031abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1041abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.pause(); 1051abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1061abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1071abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void setVolume(float volume) { 1081abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mIsEnabled) { 1091abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 1101abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1111abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.setVolume(volume); 1121abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1131abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1146ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko public void reconfigure(MediaFormat format, int audioBufferSize) { 11565fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (!mIsEnabled || format == null) { 1161abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 1171abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 11865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko String mimeType = format.getString(MediaFormat.KEY_MIME); 11965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); 12065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); 12165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko int pcmEncoding; 12265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko try { 12365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko pcmEncoding = format.getInteger(MediaFormat.KEY_PCM_ENCODING); 12465fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } catch (Exception e) { 1256ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko pcmEncoding = C.ENCODING_PCM_16BIT; 12665fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko } 1276ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko // TODO: Handle non-AC3. 12865fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko if (MediaFormat.MIMETYPE_AUDIO_AC3.equalsIgnoreCase(mimeType) && channelCount != 2) { 12965fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko // Workarounds b/25955476. 13065fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko // Since all devices and platforms does not support passthrough for non-stereo AC3, 13165fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko // It is safe to fake non-stereo AC3 as AC3 stereo which is default passthrough mode. 13265fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko // In other words, the channel count should be always 2. 13365fda1eaa94968bb55d5ded10dcb0b3f37fb05f2Nick Chalko channelCount = 2; 1342e1279b8bbe0603fb4399b25b73121bed5953c46Nick Chalko } 1356ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko if (MediaFormat.MIMETYPE_AUDIO_RAW.equalsIgnoreCase(mimeType)) { 1366ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko audioBufferSize = 1376ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko channelCount 1386ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * PCM16_FRAME_BYTES 1396ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * AC3_FRAMES_IN_ONE_SAMPLE 1406ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko * BUFFERED_SAMPLES_IN_AUDIOTRACK; 1416ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko } 1426ebde20b03db4c0d57f67acaac11832b610b966bNick Chalko mAudioTrack.configure(mimeType, channelCount, sampleRate, pcmEncoding, audioBufferSize); 1431abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1441abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1451abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void handleDiscontinuity() { 1461abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mIsEnabled) { 1471abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 1481abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1491abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.handleDiscontinuity(); 1501abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1511abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1521abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public int handleBuffer(ByteBuffer buffer, int offset, int size, long presentationTimeUs) 1531abddd9f6225298066094e20a6c29061b6af4590Nick Chalko throws AudioTrack.WriteException { 1541abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (!mIsEnabled) { 1551abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return AudioTrack.RESULT_BUFFER_CONSUMED; 1561abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1571abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return mAudioTrack.handleBuffer(buffer, offset, size, presentationTimeUs); 1581abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1591abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1601abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public void setStatus(boolean enable) { 1611abddd9f6225298066094e20a6c29061b6af4590Nick Chalko if (enable == mIsEnabled) { 1621abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return; 1631abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1641abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mAudioTrack.reset(); 1651abddd9f6225298066094e20a6c29061b6af4590Nick Chalko mIsEnabled = enable; 1661abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1671abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1681abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public boolean isEnabled() { 1691abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return mIsEnabled; 1701abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1711abddd9f6225298066094e20a6c29061b6af4590Nick Chalko 1721abddd9f6225298066094e20a6c29061b6af4590Nick Chalko // This should be used only in case of being enabled. 1731abddd9f6225298066094e20a6c29061b6af4590Nick Chalko public long getCurrentPositionUs(boolean isEnded) { 1741abddd9f6225298066094e20a6c29061b6af4590Nick Chalko return mAudioTrack.getCurrentPositionUs(isEnded); 1751abddd9f6225298066094e20a6c29061b6af4590Nick Chalko } 1761abddd9f6225298066094e20a6c29061b6af4590Nick Chalko} 177