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