1 // Copyright 2017 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.media; 6 7 import static org.junit.Assert.assertArrayEquals; 8 import static org.junit.Assert.assertEquals; 9 import static org.junit.Assert.assertTrue; 10 11 import android.media.AudioFormat; 12 import android.media.AudioTrack; 13 14 import org.junit.Test; 15 import org.junit.runner.RunWith; 16 import org.robolectric.annotation.Config; 17 18 import org.chromium.media.AudioTrackOutputStream.AudioBufferInfo; 19 import org.chromium.testing.local.LocalRobolectricTestRunner; 20 21 import java.nio.ByteBuffer; 22 import java.util.ArrayList; 23 import java.util.List; 24 import java.util.concurrent.CountDownLatch; 25 import java.util.concurrent.TimeUnit; 26 27 /** 28 * Tests for AudioTrackOutputStream. 29 */ 30 @RunWith(LocalRobolectricTestRunner.class) 31 @Config(manifest = Config.NONE) 32 public class AudioTrackOutputStreamTest { 33 static class ObservableAudioTrack extends AudioTrack { 34 private List<Byte> mReceivedData = new ArrayList<Byte>(); 35 private boolean mPartialWrite = true; 36 ObservableAudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)37 public ObservableAudioTrack(int streamType, int sampleRateInHz, int channelConfig, 38 int audioFormat, int bufferSizeInBytes, int mode) { 39 super(streamType, sampleRateInHz, channelConfig, audioFormat, bufferSizeInBytes, mode); 40 } 41 42 @Override write(ByteBuffer audioData, int sizeInBytes, int writeMode)43 public int write(ByteBuffer audioData, int sizeInBytes, int writeMode) { 44 int writternSize = mPartialWrite ? sizeInBytes / 2 : sizeInBytes; 45 mPartialWrite = !mPartialWrite; 46 47 if (writternSize > 0) { 48 byte[] array = new byte[writternSize]; 49 audioData.get(array); 50 recordData(array, 0, writternSize); 51 } 52 53 return writternSize; 54 } 55 56 @Override write(byte[] audioData, int offsetInBytes, int sizeInBytes)57 public int write(byte[] audioData, int offsetInBytes, int sizeInBytes) { 58 int writternSize = mPartialWrite ? sizeInBytes / 2 : sizeInBytes; 59 mPartialWrite = !mPartialWrite; 60 61 if (writternSize > 0) recordData(audioData, offsetInBytes, writternSize); 62 63 return writternSize; 64 } 65 recordData(byte[] audioData, int offsetInBytes, int sizeInBytes)66 private void recordData(byte[] audioData, int offsetInBytes, int sizeInBytes) { 67 for (; sizeInBytes > 0; --sizeInBytes) mReceivedData.add(audioData[offsetInBytes++]); 68 } 69 getReceivedData()70 public List<Byte> getReceivedData() { 71 return mReceivedData; 72 } 73 } 74 75 static class DataProvider implements AudioTrackOutputStream.Callback { 76 private static final int MIN_BUFFER_SIZE = 800; 77 private List<Byte> mGeneratedData = new ArrayList<Byte>(); 78 private CountDownLatch mDoneSignal; 79 private ObservableAudioTrack mAudioTrack; 80 DataProvider(int bufferCount)81 public DataProvider(int bufferCount) { 82 assert bufferCount > 0; 83 mDoneSignal = new CountDownLatch(bufferCount + 1); 84 } 85 updateBufferCount(int bufferCount)86 public void updateBufferCount(int bufferCount) { 87 assert bufferCount > 0; 88 mDoneSignal = new CountDownLatch(bufferCount + 1); 89 } 90 91 @Override getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat)92 public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) { 93 return MIN_BUFFER_SIZE; 94 } 95 96 @Override createAudioTrack(int streamType, int sampleRateInHz, int channelConfig, int audioFormat, int bufferSizeInBytes, int mode)97 public AudioTrack createAudioTrack(int streamType, int sampleRateInHz, int channelConfig, 98 int audioFormat, int bufferSizeInBytes, int mode) { 99 mAudioTrack = new ObservableAudioTrack(streamType, sampleRateInHz, channelConfig, 100 audioFormat, bufferSizeInBytes, mode); 101 return mAudioTrack; 102 } 103 104 @Override onMoreData(ByteBuffer audioData, long delayInFrames)105 public AudioBufferInfo onMoreData(ByteBuffer audioData, long delayInFrames) { 106 mDoneSignal.countDown(); 107 if (mDoneSignal.getCount() <= 0) { 108 try { 109 Thread.sleep(3); 110 } catch (Exception e) { 111 } 112 return null; 113 } 114 115 final int dataSize = MIN_BUFFER_SIZE; 116 for (int i = 0; i < dataSize; ++i) { 117 byte data = (byte) i; 118 audioData.put(data); 119 mGeneratedData.add(data); 120 } 121 return new AudioBufferInfo(dataSize, dataSize); 122 } 123 124 @Override getAddress(ByteBuffer byteBuffer)125 public long getAddress(ByteBuffer byteBuffer) { 126 return 0x10001L; 127 } 128 129 @Override onError()130 public void onError() {} 131 waitForOutOfData()132 public void waitForOutOfData() throws InterruptedException { 133 mDoneSignal.await(300, TimeUnit.MILLISECONDS); 134 } 135 getGeneratedData()136 public List<Byte> getGeneratedData() { 137 return mGeneratedData; 138 } 139 getReceivedData()140 public List<Byte> getReceivedData() { 141 return mAudioTrack.getReceivedData(); 142 } 143 getBufferSize()144 public int getBufferSize() { 145 return MIN_BUFFER_SIZE; 146 } 147 }; 148 149 @Test playSimpleBitstream()150 public void playSimpleBitstream() throws InterruptedException { 151 DataProvider provider = new DataProvider(3); 152 153 AudioTrackOutputStream stream = AudioTrackOutputStream.create(provider); 154 stream.open(2, 44100, AudioFormat.ENCODING_E_AC3); 155 stream.start(0x888); 156 157 provider.waitForOutOfData(); 158 List<Byte> generatedData = provider.getGeneratedData(); 159 List<Byte> receivedData = provider.getReceivedData(); 160 161 assertEquals(3 * provider.getBufferSize(), generatedData.size()); 162 assertArrayEquals(generatedData.toArray(), receivedData.toArray()); 163 164 stream.stop(); 165 stream.close(); 166 } 167 168 @Test playPiecewiseBitstream()169 public void playPiecewiseBitstream() throws InterruptedException { 170 DataProvider provider = new DataProvider(3); 171 172 AudioTrackOutputStream stream = AudioTrackOutputStream.create(provider); 173 stream.open(2, 44100, AudioFormat.ENCODING_E_AC3); 174 stream.start(0x888); 175 176 provider.waitForOutOfData(); 177 178 provider.updateBufferCount(3); 179 provider.waitForOutOfData(); 180 181 List<Byte> generatedData = provider.getGeneratedData(); 182 List<Byte> receivedData = provider.getReceivedData(); 183 184 assertTrue(6 * provider.getBufferSize() <= generatedData.size()); 185 assertArrayEquals(generatedData.toArray(), receivedData.toArray()); 186 187 stream.stop(); 188 stream.close(); 189 } 190 } 191