• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.tv.tuner.exoplayer.audio;
18 
19 import android.media.MediaFormat;
20 
21 import com.google.android.exoplayer.C;
22 import com.google.android.exoplayer.audio.AudioTrack;
23 
24 import java.nio.ByteBuffer;
25 
26 /**
27  * {@link AudioTrack} wrapper class for trickplay operations including FF/RW.
28  * FF/RW trickplay operations do not need framework {@link AudioTrack}.
29  * This wrapper class will do nothing in disabled status for those operations.
30  */
31 public class AudioTrackWrapper {
32     private static final int PCM16_FRAME_BYTES = 2;
33     private static final int AC3_FRAMES_IN_ONE_SAMPLE = 1536;
34     private static final int BUFFERED_SAMPLES_IN_AUDIOTRACK =
35             MpegTsDefaultAudioTrackRenderer.BUFFERED_SAMPLES_IN_AUDIOTRACK;
36     private final AudioTrack mAudioTrack = new AudioTrack();
37     private int mAudioSessionID;
38     private boolean mIsEnabled;
39 
AudioTrackWrapper()40     AudioTrackWrapper() {
41         mIsEnabled = true;
42     }
43 
resetSessionId()44     public void resetSessionId() {
45         mAudioSessionID = AudioTrack.SESSION_ID_NOT_SET;
46     }
47 
isInitialized()48     public boolean isInitialized() {
49         return mIsEnabled && mAudioTrack.isInitialized();
50     }
51 
restart()52     public void restart() {
53         if (mAudioTrack.isInitialized()) {
54             mAudioTrack.release();
55         }
56         mIsEnabled = true;
57         resetSessionId();
58     }
59 
release()60     public void release()  {
61         if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) {
62             mAudioTrack.release();
63         }
64     }
65 
initialize()66     public void initialize() throws AudioTrack.InitializationException {
67         if (!mIsEnabled) {
68             return;
69         }
70         if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) {
71             mAudioTrack.initialize(mAudioSessionID);
72         } else {
73             mAudioSessionID = mAudioTrack.initialize();
74         }
75     }
76 
reset()77     public void reset() {
78         if (!mIsEnabled) {
79             return;
80         }
81         mAudioTrack.reset();
82     }
83 
isEnded()84     public boolean isEnded() {
85         return !mIsEnabled || !mAudioTrack.hasPendingData();
86     }
87 
isReady()88     public boolean isReady() {
89         // In the case of not playing actual audio data, Audio track is always ready.
90         return !mIsEnabled || mAudioTrack.hasPendingData();
91     }
92 
play()93     public void play() {
94         if (!mIsEnabled) {
95             return;
96         }
97         mAudioTrack.play();
98     }
99 
pause()100     public void pause() {
101         if (!mIsEnabled) {
102             return;
103         }
104         mAudioTrack.pause();
105     }
106 
setVolume(float volume)107     public void setVolume(float volume) {
108         if (!mIsEnabled) {
109             return;
110         }
111         mAudioTrack.setVolume(volume);
112     }
113 
reconfigure(MediaFormat format, int audioBufferSize)114     public void reconfigure(MediaFormat format, int audioBufferSize) {
115         if (!mIsEnabled || format == null) {
116             return;
117         }
118         String mimeType = format.getString(MediaFormat.KEY_MIME);
119         int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
120         int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
121         int pcmEncoding;
122         try {
123             pcmEncoding = format.getInteger(MediaFormat.KEY_PCM_ENCODING);
124         } catch (Exception e) {
125             pcmEncoding = C.ENCODING_PCM_16BIT;
126         }
127         // TODO: Handle non-AC3.
128         if (MediaFormat.MIMETYPE_AUDIO_AC3.equalsIgnoreCase(mimeType) && channelCount != 2) {
129             // Workarounds b/25955476.
130             // Since all devices and platforms does not support passthrough for non-stereo AC3,
131             // It is safe to fake non-stereo AC3 as AC3 stereo which is default passthrough mode.
132             // In other words, the channel count should be always 2.
133             channelCount = 2;
134         }
135         if (MediaFormat.MIMETYPE_AUDIO_RAW.equalsIgnoreCase(mimeType)) {
136             audioBufferSize =
137                     channelCount
138                             * PCM16_FRAME_BYTES
139                             * AC3_FRAMES_IN_ONE_SAMPLE
140                             * BUFFERED_SAMPLES_IN_AUDIOTRACK;
141         }
142         mAudioTrack.configure(mimeType, channelCount, sampleRate, pcmEncoding, audioBufferSize);
143     }
144 
handleDiscontinuity()145     public void handleDiscontinuity() {
146         if (!mIsEnabled) {
147             return;
148         }
149         mAudioTrack.handleDiscontinuity();
150     }
151 
handleBuffer(ByteBuffer buffer, int offset, int size, long presentationTimeUs)152     public int handleBuffer(ByteBuffer buffer, int offset, int size, long presentationTimeUs)
153             throws AudioTrack.WriteException {
154         if (!mIsEnabled) {
155             return AudioTrack.RESULT_BUFFER_CONSUMED;
156         }
157         return mAudioTrack.handleBuffer(buffer, offset, size, presentationTimeUs);
158     }
159 
setStatus(boolean enable)160     public void setStatus(boolean enable) {
161         if (enable == mIsEnabled) {
162             return;
163         }
164         mAudioTrack.reset();
165         mIsEnabled = enable;
166     }
167 
isEnabled()168     public boolean isEnabled() {
169         return mIsEnabled;
170     }
171 
172     // This should be used only in case of being enabled.
getCurrentPositionUs(boolean isEnded)173     public long getCurrentPositionUs(boolean isEnded) {
174         return mAudioTrack.getCurrentPositionUs(isEnded);
175     }
176 }
177