• 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 import com.google.android.exoplayer.C;
21 import com.google.android.exoplayer.audio.AudioTrack;
22 import java.nio.ByteBuffer;
23 
24 /**
25  * {@link AudioTrack} wrapper class for trickplay operations including FF/RW. FF/RW trickplay
26  * operations do not need framework {@link AudioTrack}. This wrapper class will do nothing in
27  * disabled status for those operations.
28  */
29 public class AudioTrackWrapper {
30     private static final int PCM16_FRAME_BYTES = 2;
31     private static final int AC3_FRAMES_IN_ONE_SAMPLE = 1536;
32     private static final int BUFFERED_SAMPLES_IN_AUDIOTRACK =
33             MpegTsDefaultAudioTrackRenderer.BUFFERED_SAMPLES_IN_AUDIOTRACK;
34     private final AudioTrack mAudioTrack = new AudioTrack();
35     private int mAudioSessionID;
36     private boolean mIsEnabled;
37 
AudioTrackWrapper()38     AudioTrackWrapper() {
39         mIsEnabled = true;
40     }
41 
resetSessionId()42     public void resetSessionId() {
43         mAudioSessionID = AudioTrack.SESSION_ID_NOT_SET;
44     }
45 
isInitialized()46     public boolean isInitialized() {
47         return mIsEnabled && mAudioTrack.isInitialized();
48     }
49 
restart()50     public void restart() {
51         if (mAudioTrack.isInitialized()) {
52             mAudioTrack.release();
53         }
54         mIsEnabled = true;
55         resetSessionId();
56     }
57 
release()58     public void release() {
59         if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) {
60             mAudioTrack.release();
61         }
62     }
63 
initialize()64     public void initialize() throws AudioTrack.InitializationException {
65         if (!mIsEnabled) {
66             return;
67         }
68         if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) {
69             mAudioTrack.initialize(mAudioSessionID);
70         } else {
71             mAudioSessionID = mAudioTrack.initialize();
72         }
73     }
74 
reset()75     public void reset() {
76         if (!mIsEnabled) {
77             return;
78         }
79         mAudioTrack.reset();
80     }
81 
isEnded()82     public boolean isEnded() {
83         return !mIsEnabled || !mAudioTrack.hasPendingData();
84     }
85 
isReady()86     public boolean isReady() {
87         // In the case of not playing actual audio data, Audio track is always ready.
88         return !mIsEnabled || mAudioTrack.hasPendingData();
89     }
90 
play()91     public void play() {
92         if (!mIsEnabled) {
93             return;
94         }
95         mAudioTrack.play();
96     }
97 
pause()98     public void pause() {
99         if (!mIsEnabled) {
100             return;
101         }
102         mAudioTrack.pause();
103     }
104 
setVolume(float volume)105     public void setVolume(float volume) {
106         if (!mIsEnabled) {
107             return;
108         }
109         mAudioTrack.setVolume(volume);
110     }
111 
reconfigure(MediaFormat format, int audioBufferSize)112     public void reconfigure(MediaFormat format, int audioBufferSize) {
113         if (!mIsEnabled || format == null) {
114             return;
115         }
116         String mimeType = format.getString(MediaFormat.KEY_MIME);
117         int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
118         int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
119         int pcmEncoding;
120         try {
121             pcmEncoding = format.getInteger(MediaFormat.KEY_PCM_ENCODING);
122         } catch (Exception e) {
123             pcmEncoding = C.ENCODING_PCM_16BIT;
124         }
125         // TODO: Handle non-AC3.
126         if (MediaFormat.MIMETYPE_AUDIO_AC3.equalsIgnoreCase(mimeType) && channelCount != 2) {
127             // Workarounds b/25955476.
128             // Since all devices and platforms does not support passthrough for non-stereo AC3,
129             // It is safe to fake non-stereo AC3 as AC3 stereo which is default passthrough mode.
130             // In other words, the channel count should be always 2.
131             channelCount = 2;
132         }
133         if (MediaFormat.MIMETYPE_AUDIO_RAW.equalsIgnoreCase(mimeType)) {
134             audioBufferSize =
135                     channelCount
136                             * PCM16_FRAME_BYTES
137                             * AC3_FRAMES_IN_ONE_SAMPLE
138                             * BUFFERED_SAMPLES_IN_AUDIOTRACK;
139         }
140         mAudioTrack.configure(mimeType, channelCount, sampleRate, pcmEncoding, audioBufferSize);
141     }
142 
handleDiscontinuity()143     public void handleDiscontinuity() {
144         if (!mIsEnabled) {
145             return;
146         }
147         mAudioTrack.handleDiscontinuity();
148     }
149 
handleBuffer(ByteBuffer buffer, int offset, int size, long presentationTimeUs)150     public int handleBuffer(ByteBuffer buffer, int offset, int size, long presentationTimeUs)
151             throws AudioTrack.WriteException {
152         if (!mIsEnabled) {
153             return AudioTrack.RESULT_BUFFER_CONSUMED;
154         }
155         return mAudioTrack.handleBuffer(buffer, offset, size, presentationTimeUs);
156     }
157 
setStatus(boolean enable)158     public void setStatus(boolean enable) {
159         if (enable == mIsEnabled) {
160             return;
161         }
162         mAudioTrack.reset();
163         mIsEnabled = enable;
164     }
165 
isEnabled()166     public boolean isEnabled() {
167         return mIsEnabled;
168     }
169 
170     // This should be used only in case of being enabled.
getCurrentPositionUs(boolean isEnded)171     public long getCurrentPositionUs(boolean isEnded) {
172         return mAudioTrack.getCurrentPositionUs(isEnded);
173     }
174 }
175