blob: e17e49bc9da75b0d2a8a4c48a670c2467bb45b91 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.media;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import android.media.AudioFormat;
import android.media.AudioTrack;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.annotation.Config;
import org.chromium.media.AudioTrackOutputStream.AudioBufferInfo;
import org.chromium.testing.local.LocalRobolectricTestRunner;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Tests for AudioTrackOutputStream.
*/
@RunWith(LocalRobolectricTestRunner.class)
@Config(manifest = Config.NONE)
public class AudioTrackOutputStreamTest {
static class ObservableAudioTrack extends AudioTrack {
private List<Byte> mReceivedData = new ArrayList<Byte>();
private boolean mPartialWrite = true;
public ObservableAudioTrack(int streamType, int sampleRateInHz, int channelConfig,
int audioFormat, int bufferSizeInBytes, int mode) {
super(streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode);
}
@Override
public int write(ByteBuffer audioData, int sizeInBytes, int writeMode) {
int writternSize = mPartialWrite ? sizeInBytes / 2 : sizeInBytes;
mPartialWrite = !mPartialWrite;
if (writternSize > 0) {
byte[] array = new byte[writternSize];
audioData.get(array);
recordData(array, 0, writternSize);
}
return writternSize;
}
@Override
public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) {
int writternSize = mPartialWrite ? sizeInBytes / 2 : sizeInBytes;
mPartialWrite = !mPartialWrite;
if (writternSize > 0) recordData(audioData, offsetInBytes, writternSize);
return writternSize;
}
private void recordData(byte[] audioData, int offsetInBytes, int sizeInBytes) {
for (; sizeInBytes > 0; --sizeInBytes) mReceivedData.add(audioData[offsetInBytes++]);
}
public List<Byte> getReceivedData() {
return mReceivedData;
}
}
static class DataProvider implements AudioTrackOutputStream.Callback {
private static final int MIN_BUFFER_SIZE = 800;
private List<Byte> mGeneratedData = new ArrayList<Byte>();
private CountDownLatch mDoneSignal;
private ObservableAudioTrack mAudioTrack;
public DataProvider(int bufferCount) {
assert bufferCount > 0;
mDoneSignal = new CountDownLatch(bufferCount + 1);
}
public void updateBufferCount(int bufferCount) {
assert bufferCount > 0;
mDoneSignal = new CountDownLatch(bufferCount + 1);
}
@Override
public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
return MIN_BUFFER_SIZE;
}
@Override
public AudioTrack createAudioTrack(int streamType, int sampleRateInHz, int channelConfig,
int audioFormat, int bufferSizeInBytes, int mode) {
mAudioTrack = new ObservableAudioTrack(streamType, sampleRateInHz, channelConfig,
audioFormat, bufferSizeInBytes, mode);
return mAudioTrack;
}
@Override
public AudioBufferInfo onMoreData(ByteBuffer audioData, long delayInFrames) {
mDoneSignal.countDown();
if (mDoneSignal.getCount() <= 0) {
try {
Thread.sleep(3);
} catch (Exception e) {
}
return null;
}
final int dataSize = MIN_BUFFER_SIZE;
for (int i = 0; i < dataSize; ++i) {
byte data = (byte) i;
audioData.put(data);
mGeneratedData.add(data);
}
return new AudioBufferInfo(dataSize, dataSize);
}
@Override
public long getAddress(ByteBuffer byteBuffer) {
return 0x10001L;
}
@Override
public void onError() {}
public void waitForOutOfData() throws InterruptedException {
mDoneSignal.await(300, TimeUnit.MILLISECONDS);
}
public List<Byte> getGeneratedData() {
return mGeneratedData;
}
public List<Byte> getReceivedData() {
return mAudioTrack.getReceivedData();
}
public int getBufferSize() {
return MIN_BUFFER_SIZE;
}
};
@Test
public void playSimpleBitstream() throws InterruptedException {
DataProvider provider = new DataProvider(3);
AudioTrackOutputStream stream = AudioTrackOutputStream.create(provider);
stream.open(2, 44100, AudioFormat.ENCODING_E_AC3);
stream.start(0x888);
provider.waitForOutOfData();
List<Byte> generatedData = provider.getGeneratedData();
List<Byte> receivedData = provider.getReceivedData();
assertEquals(3 * provider.getBufferSize(), generatedData.size());
assertArrayEquals(generatedData.toArray(), receivedData.toArray());
stream.stop();
stream.close();
}
@Test
public void playPiecewiseBitstream() throws InterruptedException {
DataProvider provider = new DataProvider(3);
AudioTrackOutputStream stream = AudioTrackOutputStream.create(provider);
stream.open(2, 44100, AudioFormat.ENCODING_E_AC3);
stream.start(0x888);
provider.waitForOutOfData();
provider.updateBufferCount(3);
provider.waitForOutOfData();
List<Byte> generatedData = provider.getGeneratedData();
List<Byte> receivedData = provider.getReceivedData();
assertTrue(6 * provider.getBufferSize() <= generatedData.size());
assertArrayEquals(generatedData.toArray(), receivedData.toArray());
stream.stop();
stream.close();
}
}