blob: 953c9fc4a6c621c4000cf8b6722a24b1c9c96a5b [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tv.tuner.exoplayer.audio;
import android.media.MediaFormat;
import com.google.android.exoplayer.C;
import com.google.android.exoplayer.audio.AudioTrack;
import java.nio.ByteBuffer;
/**
* {@link AudioTrack} wrapper class for trickplay operations including FF/RW.
* FF/RW trickplay operations do not need framework {@link AudioTrack}.
* This wrapper class will do nothing in disabled status for those operations.
*/
public class AudioTrackWrapper {
private static final int PCM16_FRAME_BYTES = 2;
private static final int AC3_FRAMES_IN_ONE_SAMPLE = 1536;
private static final int BUFFERED_SAMPLES_IN_AUDIOTRACK =
MpegTsDefaultAudioTrackRenderer.BUFFERED_SAMPLES_IN_AUDIOTRACK;
private final AudioTrack mAudioTrack = new AudioTrack();
private int mAudioSessionID;
private boolean mIsEnabled;
AudioTrackWrapper() {
mIsEnabled = true;
}
public void resetSessionId() {
mAudioSessionID = AudioTrack.SESSION_ID_NOT_SET;
}
public boolean isInitialized() {
return mIsEnabled && mAudioTrack.isInitialized();
}
public void restart() {
if (mAudioTrack.isInitialized()) {
mAudioTrack.release();
}
mIsEnabled = true;
resetSessionId();
}
public void release() {
if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) {
mAudioTrack.release();
}
}
public void initialize() throws AudioTrack.InitializationException {
if (!mIsEnabled) {
return;
}
if (mAudioSessionID != AudioTrack.SESSION_ID_NOT_SET) {
mAudioTrack.initialize(mAudioSessionID);
} else {
mAudioSessionID = mAudioTrack.initialize();
}
}
public void reset() {
if (!mIsEnabled) {
return;
}
mAudioTrack.reset();
}
public boolean isEnded() {
return !mIsEnabled || !mAudioTrack.hasPendingData();
}
public boolean isReady() {
// In the case of not playing actual audio data, Audio track is always ready.
return !mIsEnabled || mAudioTrack.hasPendingData();
}
public void play() {
if (!mIsEnabled) {
return;
}
mAudioTrack.play();
}
public void pause() {
if (!mIsEnabled) {
return;
}
mAudioTrack.pause();
}
public void setVolume(float volume) {
if (!mIsEnabled) {
return;
}
mAudioTrack.setVolume(volume);
}
public void reconfigure(MediaFormat format, int audioBufferSize) {
if (!mIsEnabled || format == null) {
return;
}
String mimeType = format.getString(MediaFormat.KEY_MIME);
int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
int pcmEncoding;
try {
pcmEncoding = format.getInteger(MediaFormat.KEY_PCM_ENCODING);
} catch (Exception e) {
pcmEncoding = C.ENCODING_PCM_16BIT;
}
// TODO: Handle non-AC3.
if (MediaFormat.MIMETYPE_AUDIO_AC3.equalsIgnoreCase(mimeType) && channelCount != 2) {
// Workarounds b/25955476.
// Since all devices and platforms does not support passthrough for non-stereo AC3,
// It is safe to fake non-stereo AC3 as AC3 stereo which is default passthrough mode.
// In other words, the channel count should be always 2.
channelCount = 2;
}
if (MediaFormat.MIMETYPE_AUDIO_RAW.equalsIgnoreCase(mimeType)) {
audioBufferSize =
channelCount
* PCM16_FRAME_BYTES
* AC3_FRAMES_IN_ONE_SAMPLE
* BUFFERED_SAMPLES_IN_AUDIOTRACK;
}
mAudioTrack.configure(mimeType, channelCount, sampleRate, pcmEncoding, audioBufferSize);
}
public void handleDiscontinuity() {
if (!mIsEnabled) {
return;
}
mAudioTrack.handleDiscontinuity();
}
public int handleBuffer(ByteBuffer buffer, int offset, int size, long presentationTimeUs)
throws AudioTrack.WriteException {
if (!mIsEnabled) {
return AudioTrack.RESULT_BUFFER_CONSUMED;
}
return mAudioTrack.handleBuffer(buffer, offset, size, presentationTimeUs);
}
public void setStatus(boolean enable) {
if (enable == mIsEnabled) {
return;
}
mAudioTrack.reset();
mIsEnabled = enable;
}
public boolean isEnabled() {
return mIsEnabled;
}
// This should be used only in case of being enabled.
public long getCurrentPositionUs(boolean isEnded) {
return mAudioTrack.getCurrentPositionUs(isEnded);
}
}