1 /* 2 * Copyright (C) 2016 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 android.media.cts; 18 19 import android.annotation.RawRes; 20 import android.app.ActivityManager; 21 import android.content.Context; 22 import android.content.pm.PackageManager; 23 import android.content.res.AssetFileDescriptor; 24 import android.content.res.Resources; 25 import android.media.AudioAttributes; 26 import android.media.AudioDeviceInfo; 27 import android.media.AudioFormat; 28 import android.media.AudioManager; 29 import android.media.AudioTimestamp; 30 import android.media.AudioTrack; 31 import android.util.Log; 32 33 import com.android.compatibility.common.util.CtsAndroidTestCase; 34 35 import java.io.BufferedInputStream; 36 import java.io.ByteArrayOutputStream; 37 import java.io.InputStream; 38 import java.nio.ByteBuffer; 39 import java.nio.ByteOrder; 40 import java.nio.ShortBuffer; 41 import java.util.ArrayList; 42 import java.util.Random; 43 44 // Test the Java AudioTrack surround sound and HDMI passthrough. 45 // Most tests involve creating a track with a given format and then playing 46 // a few seconds of audio. The playback is verified by measuring the output 47 // sample rate based on the AudioTimestamps. 48 49 @NonMediaMainlineTest 50 public class AudioTrackSurroundTest extends CtsAndroidTestCase { 51 private static final String TAG = "AudioTrackSurroundTest"; 52 53 private static final double MAX_RATE_TOLERANCE_FRACTION = 0.01; 54 private static final boolean LOG_TIMESTAMPS = false; // set true for debugging 55 56 // Set this true to prefer the device that supports the particular encoding. 57 // But note that as of 3/25/2016, a bug causes Direct tracks to fail. 58 // So only set true when debugging that problem. 59 private static final boolean USE_PREFERRED_DEVICE = false; 60 61 // Should we fail if there is no PCM16 device reported by device enumeration? 62 // This can happen if, for example, an ATV set top box does not have its HDMI cable plugged in. 63 private static final boolean REQUIRE_PCM_DEVICE = false; 64 65 private final static long NANOS_PER_MILLISECOND = 1000000L; 66 private final static int MILLIS_PER_SECOND = 1000; 67 private final static long NANOS_PER_SECOND = NANOS_PER_MILLISECOND * MILLIS_PER_SECOND; 68 69 private final static int RES_AC3_SPDIF_VOICE_32000 = R.raw.voice12_32k_128kbps_15s_ac3_spdif; 70 private final static int RES_AC3_SPDIF_VOICE_44100 = R.raw.voice12_44k_128kbps_15s_ac3_spdif; 71 private final static int RES_AC3_SPDIF_VOICE_48000 = R.raw.voice12_48k_128kbps_15s_ac3_spdif; 72 private final static int RES_AC3_VOICE_48000 = R.raw.voice12_48k_128kbps_15s_ac3; 73 74 private static int mLastPlayedEncoding = AudioFormat.ENCODING_INVALID; 75 76 // Devices that support various encodings. 77 private static boolean mDeviceScanComplete = false; 78 private static AudioDeviceInfo mInfoPCM16 = null; 79 private static AudioDeviceInfo mInfoAC3 = null; 80 private static AudioDeviceInfo mInfoE_AC3 = null; 81 private static AudioDeviceInfo mInfoDTS = null; 82 private static AudioDeviceInfo mInfoDTS_HD = null; 83 private static AudioDeviceInfo mInfoIEC61937 = null; 84 log(String testName, String message)85 private static void log(String testName, String message) { 86 Log.i(TAG, "[" + testName + "] " + message); 87 } 88 logw(String testName, String message)89 private static void logw(String testName, String message) { 90 Log.w(TAG, "[" + testName + "] " + message); 91 } 92 loge(String testName, String message)93 private static void loge(String testName, String message) { 94 Log.e(TAG, "[" + testName + "] " + message); 95 } 96 97 // This is a special method that is called automatically before each test. 98 @Override setUp()99 protected void setUp() throws Exception { 100 // Note that I tried to only scan for encodings once but the static 101 // data did not persist properly. That may be a bug. 102 // For now, just scan before every test. 103 scanDevicesForEncodings(); 104 } 105 scanDevicesForEncodings()106 private void scanDevicesForEncodings() throws Exception { 107 final String MTAG = "scanDevicesForEncodings"; 108 // Scan devices to see which encodings are supported. 109 AudioManager audioManager = (AudioManager) getContext() 110 .getSystemService(Context.AUDIO_SERVICE); 111 AudioDeviceInfo[] infos = audioManager.getDevices(AudioManager.GET_DEVICES_OUTPUTS); 112 for (AudioDeviceInfo info : infos) { 113 log(MTAG, "scanning devices, name = " + info.getProductName() 114 + ", id = " + info.getId() 115 + ", " + (info.isSink() ? "sink" : "source") 116 + ", type = " + info.getType() 117 + " ------"); 118 String text = "{"; 119 for (int encoding : info.getEncodings()) { 120 text += String.format("0x%08X, ", encoding); 121 } 122 text += "}"; 123 log(MTAG, " encodings = " + text); 124 text = "{"; 125 for (int rate : info.getSampleRates()) { 126 text += rate + ", "; 127 } 128 text += "}"; 129 log(MTAG, " sample rates = " + text); 130 if (info.isSink()) { 131 for (int encoding : info.getEncodings()) { 132 switch (encoding) { 133 case AudioFormat.ENCODING_PCM_16BIT: 134 mInfoPCM16 = info; 135 log(MTAG, "mInfoPCM16 set to " + info); 136 break; 137 case AudioFormat.ENCODING_AC3: 138 mInfoAC3 = info; 139 log(MTAG, "mInfoAC3 set to " + info); 140 break; 141 case AudioFormat.ENCODING_E_AC3: 142 mInfoE_AC3 = info; 143 log(MTAG, "mInfoE_AC3 set to " + info); 144 break; 145 case AudioFormat.ENCODING_DTS: 146 mInfoDTS = info; 147 log(MTAG, "mInfoDTS set to " + info); 148 break; 149 case AudioFormat.ENCODING_DTS_HD: 150 mInfoDTS_HD = info; 151 log(MTAG, "mInfoDTS_HD set to " + info); 152 break; 153 case AudioFormat.ENCODING_IEC61937: 154 mInfoIEC61937 = info; 155 log(MTAG, "mInfoIEC61937 set to " + info); 156 break; 157 default: 158 // This is OK. It is just an encoding that we don't care about. 159 break; 160 } 161 } 162 } 163 } 164 } 165 166 // Load a resource into a byte[] loadRawResourceBytes(@awRes int id)167 private byte[] loadRawResourceBytes(@RawRes int id) throws Exception { 168 InputStream is = getContext().getResources().openRawResource(id); 169 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 170 try (BufferedInputStream bis = new BufferedInputStream(is)) { 171 for (int b = bis.read(); b != -1; b = bis.read()) { 172 bos.write(b); 173 } 174 } 175 return bos.toByteArray(); 176 } 177 178 // Load a resource into a short[] loadRawResourceShorts(@awRes int id)179 private short[] loadRawResourceShorts(@RawRes int id) throws Exception { 180 byte[] byteBuffer = loadRawResourceBytes(id); 181 ShortBuffer shortBuffer = 182 ByteBuffer.wrap(byteBuffer).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); 183 // Unfortunately, ShortBuffer.array() works with allocated buffers only. 184 short[] masterBuffer = new short[byteBuffer.length / 2]; 185 for (int i = 0; i < masterBuffer.length; i++) { 186 masterBuffer[i] = shortBuffer.get(); 187 } 188 return masterBuffer; 189 } 190 testLoadSineSweep()191 public void testLoadSineSweep() throws Exception { 192 final String TEST_NAME = "testLoadSineSweep"; 193 short[] shortData = loadRawResourceShorts(R.raw.sinesweepraw); 194 assertTrue(TEST_NAME + ": load sinesweepraw as shorts", shortData.length > 100); 195 byte[] byteData = loadRawResourceBytes(R.raw.sinesweepraw); 196 assertTrue(TEST_NAME + ": load sinesweepraw as bytes", byteData.length > shortData.length); 197 } 198 createAudioTrack(int sampleRate, int encoding, int channelConfig)199 private static AudioTrack createAudioTrack(int sampleRate, int encoding, int channelConfig) { 200 final String TEST_NAME = "createAudioTrack"; 201 int minBufferSize = AudioTrack.getMinBufferSize( 202 sampleRate, channelConfig, 203 encoding); 204 assertTrue(TEST_NAME + ": getMinBufferSize", minBufferSize > 0); 205 int bufferSize = minBufferSize * 3; // plenty big 206 AudioTrack track = new AudioTrack(AudioManager.STREAM_MUSIC, 207 sampleRate, channelConfig, 208 encoding, bufferSize, 209 AudioTrack.MODE_STREAM); 210 return track; 211 } 212 213 static class TimestampAnalyzer { 214 ArrayList<AudioTimestamp> mTimestamps = new ArrayList<AudioTimestamp>(); 215 AudioTimestamp mPreviousTimestamp = null; 216 timestampToString(AudioTimestamp timestamp)217 static String timestampToString(AudioTimestamp timestamp) { 218 if (timestamp == null) 219 return "null"; 220 return "(pos = " + timestamp.framePosition + ", nanos = " + timestamp.nanoTime + ")"; 221 } 222 223 // Add timestamp if unique and valid. addTimestamp(AudioTrack track)224 void addTimestamp(AudioTrack track) { 225 AudioTimestamp timestamp = new AudioTimestamp(); 226 boolean gotTimestamp = track.getTimestamp(timestamp); 227 if (gotTimestamp) { 228 // Only save timestamps after the data is flowing. 229 if (mPreviousTimestamp != null 230 && timestamp.framePosition > 0 231 && timestamp.nanoTime != mPreviousTimestamp.nanoTime 232 && timestamp.framePosition != mPreviousTimestamp.framePosition) { 233 mTimestamps.add(timestamp); 234 } 235 mPreviousTimestamp = timestamp; 236 } 237 } 238 checkIndividualTimestamps(int sampleRate)239 void checkIndividualTimestamps(int sampleRate) { 240 AudioTimestamp previous = null; 241 double sumDeltaSquared = 0.0; 242 int populationSize = 0; 243 double maxDeltaMillis = 0.0; 244 // Make sure the timestamps are smooth and don't go retrograde. 245 for (AudioTimestamp timestamp : mTimestamps) { 246 if (previous != null) { 247 248 assertTrue("framePosition must be monotonic", 249 timestamp.framePosition >= previous.framePosition); 250 assertTrue("nanoTime must be monotonic", 251 timestamp.nanoTime >= previous.nanoTime); 252 253 if (timestamp.framePosition > previous.framePosition) { 254 // Measure timing jitter. 255 // Calculate predicted duration based on measured rate and compare 256 // it with actual duration. 257 final double TOLERANCE_MILLIS = 2.0; 258 long elapsedFrames = timestamp.framePosition - previous.framePosition; 259 long elapsedNanos = timestamp.nanoTime - previous.nanoTime; 260 double measuredMillis = elapsedNanos / (double) NANOS_PER_MILLISECOND; 261 double expectedMillis = elapsedFrames * (double) MILLIS_PER_SECOND 262 / sampleRate; 263 double deltaMillis = measuredMillis - expectedMillis; 264 sumDeltaSquared += deltaMillis * deltaMillis; 265 populationSize++; 266 // We only issue a warning here because the CDD does not mandate a 267 // specific tolerance. 268 double absDeltaMillis = Math.abs(deltaMillis); 269 if (absDeltaMillis > TOLERANCE_MILLIS) { 270 Log.w(TAG, "measured time exceeds expected" 271 + ", srate = " + sampleRate 272 + ", frame = " + timestamp.framePosition 273 + ", expected = " + expectedMillis 274 + ", measured = " + measuredMillis + " (msec)" 275 ); 276 } 277 if (absDeltaMillis > maxDeltaMillis) { 278 maxDeltaMillis = absDeltaMillis; 279 } 280 } 281 } 282 previous = timestamp; 283 } 284 Log.d(TAG, "max abs(delta) from expected duration = " + maxDeltaMillis + " msec"); 285 if (populationSize > 0) { 286 double deviation = Math.sqrt(sumDeltaSquared / populationSize); 287 Log.d(TAG, "standard deviation from expected duration = " + deviation + " msec"); 288 } 289 } 290 291 // Use collected timestamps to estimate a sample rate. estimateSampleRate()292 double estimateSampleRate() { 293 assertTrue("expect many timestamps, got " + mTimestamps.size(), 294 mTimestamps.size() > 10); 295 // Use first and last timestamp to get the most accurate rate. 296 AudioTimestamp first = mTimestamps.get(0); 297 AudioTimestamp last = mTimestamps.get(mTimestamps.size() - 1); 298 return calculateSampleRate(first, last); 299 } 300 301 /** 302 * @param timestamp1 303 * @param timestamp2 304 */ calculateSampleRate(AudioTimestamp timestamp1, AudioTimestamp timestamp2)305 private double calculateSampleRate(AudioTimestamp timestamp1, AudioTimestamp timestamp2) { 306 long elapsedFrames = timestamp2.framePosition - timestamp1.framePosition; 307 long elapsedNanos = timestamp2.nanoTime - timestamp1.nanoTime; 308 double measuredRate = elapsedFrames * (double) NANOS_PER_SECOND / elapsedNanos; 309 if (LOG_TIMESTAMPS) { 310 Log.i(TAG, "calculateSampleRate(), elapsedFrames =, " + elapsedFrames 311 + ", measuredRate =, " 312 + (int) measuredRate); 313 } 314 return measuredRate; 315 } 316 } 317 318 // Class for looping a recording for several seconds and measuring the sample rate. 319 // This is not static because it needs to call getContext(). 320 abstract class SamplePlayerBase { 321 private final int mSampleRate; 322 private final int mEncoding; 323 private final int mChannelConfig; 324 private int mBlockSize = 512; 325 protected int mOffset = 0; 326 protected AudioTrack mTrack; 327 private final TimestampAnalyzer mTimestampAnalyzer = new TimestampAnalyzer(); 328 SamplePlayerBase(int sampleRate, int encoding, int channelConfig)329 SamplePlayerBase(int sampleRate, int encoding, int channelConfig) { 330 mSampleRate = sampleRate; 331 mEncoding = encoding; 332 mChannelConfig = channelConfig; 333 } 334 335 // Use abstract write to handle byte[] or short[] data. writeBlock(int numSamples)336 protected abstract int writeBlock(int numSamples); 337 primeBuffer()338 private int primeBuffer() { 339 // Will not block when track is stopped. 340 return writeBlock(Integer.MAX_VALUE); 341 } 342 343 // Add a warning to the assert message that might help folks figure out why their 344 // PCM test is failing. getPcmWarning()345 private String getPcmWarning() { 346 return (mInfoPCM16 == null && AudioFormat.isEncodingLinearPcm(mEncoding)) 347 ? " (No PCM device!)" : ""; 348 } 349 350 /** 351 * Use a device that we know supports the current encoding. 352 */ usePreferredDevice()353 private void usePreferredDevice() { 354 AudioDeviceInfo info = null; 355 switch (mEncoding) { 356 case AudioFormat.ENCODING_PCM_16BIT: 357 info = mInfoPCM16; 358 break; 359 case AudioFormat.ENCODING_AC3: 360 info = mInfoAC3; 361 break; 362 case AudioFormat.ENCODING_E_AC3: 363 info = mInfoE_AC3; 364 break; 365 case AudioFormat.ENCODING_DTS: 366 info = mInfoDTS; 367 break; 368 case AudioFormat.ENCODING_DTS_HD: 369 info = mInfoDTS_HD; 370 break; 371 case AudioFormat.ENCODING_IEC61937: 372 info = mInfoIEC61937; 373 break; 374 default: 375 break; 376 } 377 378 if (info != null) { 379 log(TAG, "track.setPreferredDevice(" + info + ")"); 380 mTrack.setPreferredDevice(info); 381 } 382 } 383 playAndMeasureRate()384 public void playAndMeasureRate() throws Exception { 385 final String TEST_NAME = "playAndMeasureRate"; 386 final long TEST_DURATION_MILLIS = 5000; // just long enough to measure the rate 387 388 if (mLastPlayedEncoding == AudioFormat.ENCODING_INVALID || 389 !AudioFormat.isEncodingLinearPcm(mEncoding) || 390 !AudioFormat.isEncodingLinearPcm(mLastPlayedEncoding)) { 391 Log.d(TAG, "switching from format: " + mLastPlayedEncoding 392 + " to: " + mEncoding 393 + " requires sleep"); 394 // Switching between compressed formats may require 395 // some time for the HAL to adjust and give proper timing. 396 // One second should be ok, but we use 2 just in case. 397 Thread.sleep(2000 /* millis */); 398 } 399 mLastPlayedEncoding = mEncoding; 400 401 log(TEST_NAME, String.format("test using rate = %d, encoding = 0x%08x", 402 mSampleRate, mEncoding)); 403 // Create a track and prime it. 404 mTrack = createAudioTrack(mSampleRate, mEncoding, mChannelConfig); 405 try { 406 assertEquals(TEST_NAME + ": track created" + getPcmWarning(), 407 AudioTrack.STATE_INITIALIZED, 408 mTrack.getState()); 409 410 if (USE_PREFERRED_DEVICE) { 411 usePreferredDevice(); 412 } 413 414 int bytesWritten = 0; 415 mOffset = primeBuffer(); // prime the buffer 416 assertTrue(TEST_NAME + ": priming offset = " + mOffset + getPcmWarning(), 417 mOffset > 0); 418 bytesWritten += mOffset; 419 420 // Play for a while. 421 mTrack.play(); 422 423 log(TEST_NAME, "native rate = " 424 + mTrack.getNativeOutputSampleRate(mTrack.getStreamType())); 425 long elapsedMillis = 0; 426 long startTime = System.currentTimeMillis(); 427 while (elapsedMillis < TEST_DURATION_MILLIS) { 428 writeBlock(mBlockSize); 429 elapsedMillis = System.currentTimeMillis() - startTime; 430 mTimestampAnalyzer.addTimestamp(mTrack); 431 } 432 433 // Did we underrun? Allow 0 or 1 because there is sometimes 434 // an underrun on startup. 435 int underrunCount1 = mTrack.getUnderrunCount(); 436 assertTrue(TEST_NAME + ": too many underruns, got underrunCount1" + getPcmWarning(), 437 underrunCount1 < 2); 438 439 // Estimate the sample rate and compare it with expected. 440 double estimatedRate = mTimestampAnalyzer.estimateSampleRate(); 441 Log.d(TAG, "measured sample rate = " + estimatedRate); 442 assertEquals(TEST_NAME + ": measured sample rate" + getPcmWarning(), 443 mSampleRate, estimatedRate, mSampleRate * MAX_RATE_TOLERANCE_FRACTION); 444 445 // Check for jitter or retrograde motion in each timestamp. 446 mTimestampAnalyzer.checkIndividualTimestamps(mSampleRate); 447 448 } finally { 449 mTrack.release(); 450 } 451 } 452 } 453 454 // Create player for short[] 455 class SamplePlayerShorts extends SamplePlayerBase { 456 private final short[] mData; 457 SamplePlayerShorts(int sampleRate, int encoding, int channelConfig)458 SamplePlayerShorts(int sampleRate, int encoding, int channelConfig) { 459 super(sampleRate, encoding, channelConfig); 460 mData = new short[64 * 1024]; 461 // Fill with noise. We should not hear the noise for IEC61937. 462 int amplitude = 8000; 463 Random random = new Random(); 464 for (int i = 0; i < mData.length; i++) { 465 mData[i] = (short)(random.nextInt(amplitude) - (amplitude / 2)); 466 } 467 } 468 SamplePlayerShorts(int sampleRate, int encoding, int channelConfig, @RawRes int resourceId)469 SamplePlayerShorts(int sampleRate, int encoding, int channelConfig, @RawRes int resourceId) 470 throws Exception { 471 super(sampleRate, encoding, channelConfig); 472 mData = loadRawResourceShorts(resourceId); 473 assertTrue("SamplePlayerShorts: load resource file as shorts", mData.length > 0); 474 } 475 476 @Override writeBlock(int numShorts)477 protected int writeBlock(int numShorts) { 478 int result = 0; 479 int shortsToWrite = numShorts; 480 int shortsLeft = mData.length - mOffset; 481 if (shortsToWrite > shortsLeft) { 482 shortsToWrite = shortsLeft; 483 } 484 if (shortsToWrite > 0) { 485 result = mTrack.write(mData, mOffset, shortsToWrite); 486 mOffset += result; 487 } else { 488 mOffset = 0; // rewind 489 } 490 return result; 491 } 492 } 493 494 // Create player for byte[] 495 class SamplePlayerBytes extends SamplePlayerBase { 496 private final byte[] mData; 497 SamplePlayerBytes(int sampleRate, int encoding, int channelConfig)498 SamplePlayerBytes(int sampleRate, int encoding, int channelConfig) { 499 super(sampleRate, encoding, channelConfig); 500 mData = new byte[128 * 1024]; 501 } 502 SamplePlayerBytes(int sampleRate, int encoding, int channelConfig, @RawRes int resourceId)503 SamplePlayerBytes(int sampleRate, int encoding, int channelConfig, @RawRes int resourceId) 504 throws Exception { 505 super(sampleRate, encoding, channelConfig); 506 mData = loadRawResourceBytes(resourceId); 507 assertTrue("SamplePlayerBytes: load resource file as bytes", mData.length > 0); 508 } 509 510 @Override writeBlock(int numBytes)511 protected int writeBlock(int numBytes) { 512 int result = 0; 513 int bytesToWrite = numBytes; 514 int bytesLeft = mData.length - mOffset; 515 if (bytesToWrite > bytesLeft) { 516 bytesToWrite = bytesLeft; 517 } 518 if (bytesToWrite > 0) { 519 result = mTrack.write(mData, mOffset, bytesToWrite); 520 mOffset += result; 521 } else { 522 mOffset = 0; // rewind 523 } 524 return result; 525 } 526 } 527 testPlayAC3Bytes()528 public void testPlayAC3Bytes() throws Exception { 529 if (mInfoAC3 != null) { 530 SamplePlayerBytes player = new SamplePlayerBytes( 531 48000, AudioFormat.ENCODING_AC3, AudioFormat.CHANNEL_OUT_STEREO, 532 RES_AC3_VOICE_48000); 533 player.playAndMeasureRate(); 534 } 535 } 536 testPlayAC3Shorts()537 public void testPlayAC3Shorts() throws Exception { 538 if (mInfoAC3 != null) { 539 SamplePlayerShorts player = new SamplePlayerShorts( 540 48000, AudioFormat.ENCODING_AC3, AudioFormat.CHANNEL_OUT_STEREO, 541 RES_AC3_VOICE_48000); 542 player.playAndMeasureRate(); 543 } 544 } 545 testPlayIEC61937_32000()546 public void testPlayIEC61937_32000() throws Exception { 547 if (mInfoIEC61937 != null) { 548 SamplePlayerShorts player = new SamplePlayerShorts( 549 32000, AudioFormat.ENCODING_IEC61937, AudioFormat.CHANNEL_OUT_STEREO, 550 RES_AC3_SPDIF_VOICE_32000); 551 player.playAndMeasureRate(); 552 } 553 } 554 testPlayIEC61937_44100()555 public void testPlayIEC61937_44100() throws Exception { 556 if (mInfoIEC61937 != null) { 557 SamplePlayerShorts player = new SamplePlayerShorts( 558 44100, AudioFormat.ENCODING_IEC61937, AudioFormat.CHANNEL_OUT_STEREO, 559 RES_AC3_SPDIF_VOICE_44100); 560 player.playAndMeasureRate(); 561 } 562 } 563 testPlayIEC61937_48000()564 public void testPlayIEC61937_48000() throws Exception { 565 if (mInfoIEC61937 != null) { 566 SamplePlayerShorts player = new SamplePlayerShorts( 567 48000, AudioFormat.ENCODING_IEC61937, AudioFormat.CHANNEL_OUT_STEREO, 568 RES_AC3_SPDIF_VOICE_48000); 569 player.playAndMeasureRate(); 570 } 571 } 572 testIEC61937_Errors()573 public void testIEC61937_Errors() throws Exception { 574 if (mInfoIEC61937 != null) { 575 final String TEST_NAME = "testIEC61937_Errors"; 576 try { 577 AudioTrack track = createAudioTrack(48000, AudioFormat.ENCODING_IEC61937, 578 AudioFormat.CHANNEL_OUT_MONO); 579 assertTrue(TEST_NAME + ": IEC61937 track creation should fail for mono", false); 580 } catch (IllegalArgumentException e) { 581 // This is expected behavior. 582 } 583 584 try { 585 AudioTrack track = createAudioTrack(48000, AudioFormat.ENCODING_IEC61937, 586 AudioFormat.CHANNEL_OUT_5POINT1); 587 assertTrue(TEST_NAME + ": IEC61937 track creation should fail for 5.1", false); 588 } catch (IllegalArgumentException e) { 589 // This is expected behavior. 590 } 591 } 592 } 593 testPcmSupport()594 public void testPcmSupport() throws Exception { 595 if (REQUIRE_PCM_DEVICE) { 596 // There should always be a fake PCM device available. 597 assertTrue("testPcmSupport: PCM should be supported." 598 + " On ATV device please check HDMI connection.", 599 mInfoPCM16 != null); 600 } 601 } 602 isPcmTestingEnabled()603 private boolean isPcmTestingEnabled() { 604 return (mInfoPCM16 != null || !REQUIRE_PCM_DEVICE); 605 } 606 testPlaySineSweepShorts()607 public void testPlaySineSweepShorts() throws Exception { 608 if (isPcmTestingEnabled()) { 609 SamplePlayerShorts player = new SamplePlayerShorts( 610 44100, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_STEREO, 611 R.raw.sinesweepraw); 612 player.playAndMeasureRate(); 613 } 614 } 615 testPlaySineSweepBytes()616 public void testPlaySineSweepBytes() throws Exception { 617 if (isPcmTestingEnabled()) { 618 SamplePlayerBytes player = new SamplePlayerBytes( 619 44100, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_STEREO, 620 R.raw.sinesweepraw); 621 player.playAndMeasureRate(); 622 } 623 } 624 testPlaySineSweepBytes48000()625 public void testPlaySineSweepBytes48000() throws Exception { 626 if (isPcmTestingEnabled()) { 627 SamplePlayerBytes player = new SamplePlayerBytes( 628 48000, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_STEREO, 629 R.raw.sinesweepraw); 630 player.playAndMeasureRate(); 631 } 632 } 633 testPlaySineSweepShortsMono()634 public void testPlaySineSweepShortsMono() throws Exception { 635 if (isPcmTestingEnabled()) { 636 SamplePlayerShorts player = new SamplePlayerShorts(44100, AudioFormat.ENCODING_PCM_16BIT, 637 AudioFormat.CHANNEL_OUT_MONO, 638 R.raw.sinesweepraw); 639 player.playAndMeasureRate(); 640 } 641 } 642 testPlaySineSweepBytesMono()643 public void testPlaySineSweepBytesMono() 644 throws Exception { 645 if (isPcmTestingEnabled()) { 646 SamplePlayerBytes player = new SamplePlayerBytes(44100, 647 AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_MONO, R.raw.sinesweepraw); 648 player.playAndMeasureRate(); 649 } 650 } 651 652 } 653