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