1 /* 2 * Copyright (C) 2022 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 package android.virtualdevice.cts; 17 18 import static android.Manifest.permission.ACTIVITY_EMBEDDING; 19 import static android.Manifest.permission.ADD_ALWAYS_UNLOCKED_DISPLAY; 20 import static android.Manifest.permission.ADD_TRUSTED_DISPLAY; 21 import static android.Manifest.permission.CAPTURE_AUDIO_OUTPUT; 22 import static android.Manifest.permission.CREATE_VIRTUAL_DEVICE; 23 import static android.Manifest.permission.MODIFY_AUDIO_ROUTING; 24 import static android.Manifest.permission.REAL_GET_TASKS; 25 import static android.Manifest.permission.WAKE_LOCK; 26 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; 27 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_TRUSTED; 28 import static android.media.AudioFormat.CHANNEL_IN_MONO; 29 import static android.media.AudioFormat.ENCODING_PCM_16BIT; 30 import static android.media.AudioFormat.ENCODING_PCM_FLOAT; 31 import static android.media.AudioRecord.READ_BLOCKING; 32 import static android.media.AudioRecord.RECORDSTATE_RECORDING; 33 import static android.media.AudioRecord.RECORDSTATE_STOPPED; 34 import static android.media.AudioTrack.PLAYSTATE_PLAYING; 35 import static android.media.AudioTrack.PLAYSTATE_STOPPED; 36 import static android.media.AudioTrack.WRITE_BLOCKING; 37 import static android.media.AudioTrack.WRITE_NON_BLOCKING; 38 import static android.virtualdevice.cts.common.ActivityResultReceiver.EXTRA_LAST_RECORDED_NONZERO_VALUE; 39 import static android.virtualdevice.cts.common.ActivityResultReceiver.EXTRA_POWER_SPECTRUM_AT_FREQUENCY; 40 import static android.virtualdevice.cts.common.ActivityResultReceiver.EXTRA_POWER_SPECTRUM_NOT_FREQUENCY; 41 import static android.virtualdevice.cts.common.AudioHelper.ACTION_PLAY_AUDIO; 42 import static android.virtualdevice.cts.common.AudioHelper.ACTION_RECORD_AUDIO; 43 import static android.virtualdevice.cts.common.AudioHelper.AMPLITUDE; 44 import static android.virtualdevice.cts.common.AudioHelper.BUFFER_SIZE_IN_BYTES; 45 import static android.virtualdevice.cts.common.AudioHelper.BYTE_ARRAY; 46 import static android.virtualdevice.cts.common.AudioHelper.BYTE_BUFFER; 47 import static android.virtualdevice.cts.common.AudioHelper.BYTE_VALUE; 48 import static android.virtualdevice.cts.common.AudioHelper.CHANNEL_COUNT; 49 import static android.virtualdevice.cts.common.AudioHelper.EXTRA_AUDIO_DATA_TYPE; 50 import static android.virtualdevice.cts.common.AudioHelper.FLOAT_ARRAY; 51 import static android.virtualdevice.cts.common.AudioHelper.FLOAT_VALUE; 52 import static android.virtualdevice.cts.common.AudioHelper.FREQUENCY; 53 import static android.virtualdevice.cts.common.AudioHelper.NUMBER_OF_SAMPLES; 54 import static android.virtualdevice.cts.common.AudioHelper.SAMPLE_RATE; 55 import static android.virtualdevice.cts.common.AudioHelper.SHORT_ARRAY; 56 import static android.virtualdevice.cts.common.AudioHelper.SHORT_VALUE; 57 import static android.virtualdevice.cts.util.TestAppHelper.MAIN_ACTIVITY_COMPONENT; 58 import static android.virtualdevice.cts.util.VirtualDeviceTestUtils.createActivityOptions; 59 60 import static androidx.test.core.app.ApplicationProvider.getApplicationContext; 61 62 import static com.google.common.truth.Truth.assertThat; 63 64 import static org.junit.Assume.assumeFalse; 65 import static org.junit.Assume.assumeTrue; 66 import static org.mockito.ArgumentMatchers.any; 67 import static org.mockito.Mockito.timeout; 68 import static org.mockito.Mockito.verify; 69 70 import android.companion.virtual.VirtualDeviceManager; 71 import android.companion.virtual.VirtualDeviceManager.VirtualDevice; 72 import android.companion.virtual.VirtualDeviceParams; 73 import android.companion.virtual.audio.AudioCapture; 74 import android.companion.virtual.audio.AudioInjection; 75 import android.companion.virtual.audio.VirtualAudioDevice; 76 import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback; 77 import android.content.Context; 78 import android.content.Intent; 79 import android.content.pm.PackageManager; 80 import android.hardware.display.VirtualDisplay; 81 import android.media.AudioFormat; 82 import android.platform.test.annotations.AppModeFull; 83 import android.virtualdevice.cts.common.ActivityResultReceiver; 84 import android.virtualdevice.cts.common.AudioHelper; 85 import android.virtualdevice.cts.util.FakeAssociationRule; 86 87 import androidx.test.ext.junit.runners.AndroidJUnit4; 88 import androidx.test.platform.app.InstrumentationRegistry; 89 90 import com.android.compatibility.common.util.AdoptShellPermissionsRule; 91 92 import org.junit.After; 93 import org.junit.Before; 94 import org.junit.Rule; 95 import org.junit.Test; 96 import org.junit.runner.RunWith; 97 import org.mockito.ArgumentCaptor; 98 import org.mockito.Captor; 99 import org.mockito.Mock; 100 import org.mockito.MockitoAnnotations; 101 102 import java.nio.ByteBuffer; 103 import java.nio.ByteOrder; 104 105 /** 106 * Tests for injection and capturing of audio from streamed apps 107 */ 108 @RunWith(AndroidJUnit4.class) 109 @AppModeFull(reason = "VirtualDeviceManager cannot be accessed by instant apps") 110 public class VirtualAudioTest { 111 /** 112 * Captured signal should be mostly single frequency and power of that frequency should be 113 * over this much of total power. 114 */ 115 public static final double POWER_THRESHOLD_FOR_PRESENT = 0.4f; 116 117 /** 118 * The other signals should have very weak power and should not exceed this value 119 */ 120 public static final double POWER_THRESHOLD_FOR_ABSENT = 0.02f; 121 122 private static final VirtualDeviceParams DEFAULT_VIRTUAL_DEVICE_PARAMS = 123 new VirtualDeviceParams.Builder().build(); 124 125 @Rule 126 public AdoptShellPermissionsRule mAdoptShellPermissionsRule = new AdoptShellPermissionsRule( 127 InstrumentationRegistry.getInstrumentation().getUiAutomation(), 128 ACTIVITY_EMBEDDING, 129 ADD_ALWAYS_UNLOCKED_DISPLAY, 130 ADD_TRUSTED_DISPLAY, 131 CREATE_VIRTUAL_DEVICE, 132 REAL_GET_TASKS, 133 WAKE_LOCK, 134 MODIFY_AUDIO_ROUTING, 135 CAPTURE_AUDIO_OUTPUT); 136 @Rule 137 public FakeAssociationRule mFakeAssociationRule = new FakeAssociationRule(); 138 139 private VirtualDevice mVirtualDevice; 140 private VirtualDisplay mVirtualDisplay; 141 private VirtualAudioDevice mVirtualAudioDevice; 142 143 @Mock 144 private VirtualDisplay.Callback mVirtualDisplayCallback; 145 @Mock 146 private AudioConfigurationChangeCallback mAudioConfigurationChangeCallback; 147 @Mock 148 private ActivityResultReceiver.Callback mActivityResultCallback; 149 @Captor 150 private ArgumentCaptor<Intent> mIntentCaptor; 151 152 @Before setUp()153 public void setUp() throws Exception { 154 MockitoAnnotations.initMocks(this); 155 Context context = getApplicationContext(); 156 PackageManager packageManager = context.getPackageManager(); 157 assumeTrue(packageManager.hasSystemFeature(PackageManager.FEATURE_COMPANION_DEVICE_SETUP)); 158 assumeTrue(packageManager.hasSystemFeature( 159 PackageManager.FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS)); 160 assumeFalse("Skipping test: not supported on automotive", isAutomotive()); 161 // TODO(b/261155110): Re-enable tests once freeform mode is supported in Virtual Display. 162 assumeFalse("Skipping test: VirtualDisplay window policy doesn't support freeform.", 163 packageManager.hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)); 164 165 VirtualDeviceManager vdm = context.getSystemService(VirtualDeviceManager.class); 166 mVirtualDevice = vdm.createVirtualDevice( 167 mFakeAssociationRule.getAssociationInfo().getId(), 168 DEFAULT_VIRTUAL_DEVICE_PARAMS); 169 mVirtualDisplay = mVirtualDevice.createVirtualDisplay( 170 /* width= */ 100, 171 /* height= */ 100, 172 /* densityDpi= */ 240, 173 /* surface= */ null, 174 /* flags= */ VIRTUAL_DISPLAY_FLAG_TRUSTED, 175 Runnable::run, 176 mVirtualDisplayCallback); 177 } 178 179 @After tearDown()180 public void tearDown() { 181 if (mVirtualDevice != null) { 182 mVirtualDevice.close(); 183 } 184 if (mVirtualDisplay != null) { 185 mVirtualDisplay.release(); 186 } 187 if (mVirtualAudioDevice != null) { 188 mVirtualAudioDevice.close(); 189 } 190 } 191 192 @Test audioCapture_createCorrectly()193 public void audioCapture_createCorrectly() { 194 mVirtualAudioDevice = mVirtualDevice.createVirtualAudioDevice( 195 mVirtualDisplay, /* executor= */ null, /* callback= */ null); 196 AudioFormat audioFormat = createCaptureFormat(ENCODING_PCM_16BIT); 197 AudioCapture audioCapture = mVirtualAudioDevice.startAudioCapture(audioFormat); 198 assertThat(audioCapture).isNotNull(); 199 assertThat(audioCapture.getFormat()).isEqualTo(audioFormat); 200 assertThat(mVirtualAudioDevice.getAudioCapture()).isEqualTo(audioCapture); 201 202 audioCapture.startRecording(); 203 assertThat(audioCapture.getRecordingState()).isEqualTo(RECORDSTATE_RECORDING); 204 audioCapture.stop(); 205 assertThat(audioCapture.getRecordingState()).isEqualTo(RECORDSTATE_STOPPED); 206 } 207 208 @Test audioInjection_createCorrectly()209 public void audioInjection_createCorrectly() { 210 mVirtualAudioDevice = mVirtualDevice.createVirtualAudioDevice( 211 mVirtualDisplay, /* executor= */ null, /* callback= */ null); 212 AudioFormat audioFormat = createInjectionFormat(ENCODING_PCM_16BIT); 213 AudioInjection audioInjection = mVirtualAudioDevice.startAudioInjection(audioFormat); 214 assertThat(audioInjection).isNotNull(); 215 assertThat(audioInjection.getFormat()).isEqualTo(audioFormat); 216 assertThat(mVirtualAudioDevice.getAudioInjection()).isEqualTo(audioInjection); 217 218 audioInjection.play(); 219 assertThat(audioInjection.getPlayState()).isEqualTo(PLAYSTATE_PLAYING); 220 audioInjection.stop(); 221 assertThat(audioInjection.getPlayState()).isEqualTo(PLAYSTATE_STOPPED); 222 } 223 224 @Test audioCapture_receivesAudioConfigurationChangeCallback()225 public void audioCapture_receivesAudioConfigurationChangeCallback() { 226 mVirtualAudioDevice = mVirtualDevice.createVirtualAudioDevice( 227 mVirtualDisplay, /* executor= */ null, mAudioConfigurationChangeCallback); 228 AudioFormat audioFormat = createCaptureFormat(ENCODING_PCM_16BIT); 229 mVirtualAudioDevice.startAudioCapture(audioFormat); 230 231 ActivityResultReceiver activityResultReceiver = new ActivityResultReceiver( 232 getApplicationContext()); 233 activityResultReceiver.register(mActivityResultCallback); 234 InstrumentationRegistry.getInstrumentation().getTargetContext().startActivity( 235 createPlayAudioIntent(BYTE_BUFFER), 236 createActivityOptions(mVirtualDisplay)); 237 verify(mAudioConfigurationChangeCallback, timeout(5000).atLeastOnce()) 238 .onPlaybackConfigChanged(any()); 239 verify(mActivityResultCallback, timeout(5000)).onActivityResult( 240 mIntentCaptor.capture()); 241 activityResultReceiver.unregister(); 242 } 243 244 @Test audioInjection_receivesAudioConfigurationChangeCallback()245 public void audioInjection_receivesAudioConfigurationChangeCallback() { 246 mVirtualAudioDevice = mVirtualDevice.createVirtualAudioDevice( 247 mVirtualDisplay, /* executor= */ null, mAudioConfigurationChangeCallback); 248 AudioFormat audioFormat = createInjectionFormat(ENCODING_PCM_16BIT); 249 AudioInjection audioInjection = mVirtualAudioDevice.startAudioInjection(audioFormat); 250 251 ActivityResultReceiver activityResultReceiver = new ActivityResultReceiver( 252 getApplicationContext()); 253 activityResultReceiver.register(mActivityResultCallback); 254 InstrumentationRegistry.getInstrumentation().getTargetContext().startActivity( 255 createAudioRecordIntent(BYTE_BUFFER), 256 createActivityOptions(mVirtualDisplay)); 257 258 ByteBuffer byteBuffer = AudioHelper.createAudioData( 259 SAMPLE_RATE, NUMBER_OF_SAMPLES, CHANNEL_COUNT, FREQUENCY, AMPLITUDE); 260 int remaining = byteBuffer.remaining(); 261 while (remaining > 0) { 262 remaining -= audioInjection.write(byteBuffer, byteBuffer.remaining(), WRITE_BLOCKING); 263 } 264 265 verify(mAudioConfigurationChangeCallback, timeout(5000).atLeastOnce()) 266 .onRecordingConfigChanged(any()); 267 verify(mActivityResultCallback, timeout(5000)).onActivityResult( 268 mIntentCaptor.capture()); 269 activityResultReceiver.unregister(); 270 } 271 272 @Test audioCapture_readByteBuffer_shouldCaptureAppPlaybackFrequency()273 public void audioCapture_readByteBuffer_shouldCaptureAppPlaybackFrequency() { 274 runAudioCaptureTest(BYTE_BUFFER, /* readMode= */ -1); 275 } 276 277 @Test audioCapture_readByteBufferBlocking_shouldCaptureAppPlaybackFrequency()278 public void audioCapture_readByteBufferBlocking_shouldCaptureAppPlaybackFrequency() { 279 runAudioCaptureTest(BYTE_BUFFER, /* readMode= */ READ_BLOCKING); 280 } 281 282 @Test audioCapture_readByteArray_shouldCaptureAppPlaybackData()283 public void audioCapture_readByteArray_shouldCaptureAppPlaybackData() { 284 runAudioCaptureTest(BYTE_ARRAY, /* readMode= */ -1); 285 } 286 287 @Test audioCapture_readByteArrayBlocking_shouldCaptureAppPlaybackData()288 public void audioCapture_readByteArrayBlocking_shouldCaptureAppPlaybackData() { 289 runAudioCaptureTest(BYTE_ARRAY, /* readMode= */ READ_BLOCKING); 290 } 291 292 @Test audioCapture_readShortArray_shouldCaptureAppPlaybackData()293 public void audioCapture_readShortArray_shouldCaptureAppPlaybackData() { 294 runAudioCaptureTest(SHORT_ARRAY, /* readMode= */ -1); 295 } 296 297 @Test audioCapture_readShortArrayBlocking_shouldCaptureAppPlaybackData()298 public void audioCapture_readShortArrayBlocking_shouldCaptureAppPlaybackData() { 299 runAudioCaptureTest(SHORT_ARRAY, /* readMode= */ READ_BLOCKING); 300 } 301 302 @Test audioCapture_readFloatArray_shouldCaptureAppPlaybackData()303 public void audioCapture_readFloatArray_shouldCaptureAppPlaybackData() { 304 runAudioCaptureTest(FLOAT_ARRAY, /* readMode= */ READ_BLOCKING); 305 } 306 307 @Test audioInjection_writeByteBuffer_appShouldRecordInjectedFrequency()308 public void audioInjection_writeByteBuffer_appShouldRecordInjectedFrequency() { 309 runAudioInjectionTest(BYTE_BUFFER, /* writeMode= */ 310 WRITE_BLOCKING, /* timestamp= */ 0); 311 } 312 313 @Test audioInjection_writeByteBufferWithTimestamp_appShouldRecordInjectedFrequency()314 public void audioInjection_writeByteBufferWithTimestamp_appShouldRecordInjectedFrequency() { 315 runAudioInjectionTest(BYTE_BUFFER, /* writeMode= */ 316 WRITE_BLOCKING, /* timestamp= */ 50); 317 } 318 319 @Test audioInjection_writeByteArray_appShouldRecordInjectedData()320 public void audioInjection_writeByteArray_appShouldRecordInjectedData() { 321 runAudioInjectionTest(BYTE_ARRAY, /* writeMode= */ -1, /* timestamp= */ 0); 322 } 323 324 @Test audioInjection_writeByteArrayBlocking_appShouldRecordInjectedData()325 public void audioInjection_writeByteArrayBlocking_appShouldRecordInjectedData() { 326 runAudioInjectionTest(BYTE_ARRAY, /* writeMode= */ WRITE_BLOCKING, /* timestamp= */ 327 0); 328 } 329 330 @Test audioInjection_writeShortArray_appShouldRecordInjectedData()331 public void audioInjection_writeShortArray_appShouldRecordInjectedData() { 332 runAudioInjectionTest(SHORT_ARRAY, /* writeMode= */ -1, /* timestamp= */ 0); 333 } 334 335 @Test audioInjection_writeShortArrayBlocking_appShouldRecordInjectedData()336 public void audioInjection_writeShortArrayBlocking_appShouldRecordInjectedData() { 337 runAudioInjectionTest(SHORT_ARRAY, /* writeMode= */ 338 WRITE_BLOCKING, /* timestamp= */ 0); 339 } 340 341 @Test audioInjection_writeFloatArray_appShouldRecordInjectedData()342 public void audioInjection_writeFloatArray_appShouldRecordInjectedData() { 343 runAudioInjectionTest(FLOAT_ARRAY, /* writeMode= */ 344 WRITE_BLOCKING, /* timestamp= */ 0); 345 } 346 isAutomotive()347 private boolean isAutomotive() { 348 return getApplicationContext().getPackageManager() 349 .hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 350 } 351 runAudioCaptureTest(@udioHelper.DataType int dataType, int readMode)352 private void runAudioCaptureTest(@AudioHelper.DataType int dataType, int readMode) { 353 mVirtualAudioDevice = mVirtualDevice.createVirtualAudioDevice( 354 mVirtualDisplay, /* executor= */ null, /* callback= */ null); 355 int encoding = dataType == FLOAT_ARRAY ? ENCODING_PCM_FLOAT : ENCODING_PCM_16BIT; 356 AudioCapture audioCapture = mVirtualAudioDevice.startAudioCapture( 357 createCaptureFormat(encoding)); 358 359 ActivityResultReceiver activityResultReceiver = new ActivityResultReceiver( 360 getApplicationContext()); 361 activityResultReceiver.register(mActivityResultCallback); 362 InstrumentationRegistry.getInstrumentation().getTargetContext().startActivity( 363 createPlayAudioIntent(dataType), 364 createActivityOptions(mVirtualDisplay)); 365 366 AudioHelper.CapturedAudio capturedAudio = null; 367 switch (dataType) { 368 case BYTE_BUFFER: 369 ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE_IN_BYTES).order( 370 ByteOrder.nativeOrder()); 371 capturedAudio = new AudioHelper.CapturedAudio(audioCapture, byteBuffer, readMode); 372 assertThat(capturedAudio.getPowerSpectrum(FREQUENCY + 100)) 373 .isLessThan(POWER_THRESHOLD_FOR_ABSENT); 374 assertThat(capturedAudio.getPowerSpectrum(FREQUENCY)) 375 .isGreaterThan(POWER_THRESHOLD_FOR_PRESENT); 376 break; 377 case BYTE_ARRAY: 378 byte[] byteArray = new byte[BUFFER_SIZE_IN_BYTES]; 379 capturedAudio = new AudioHelper.CapturedAudio(audioCapture, byteArray, readMode); 380 assertThat(capturedAudio.getByteValue()).isEqualTo(BYTE_VALUE); 381 break; 382 case SHORT_ARRAY: 383 short[] shortArray = new short[BUFFER_SIZE_IN_BYTES / 2]; 384 capturedAudio = new AudioHelper.CapturedAudio(audioCapture, shortArray, readMode); 385 assertThat(capturedAudio.getShortValue()).isEqualTo(SHORT_VALUE); 386 break; 387 case FLOAT_ARRAY: 388 float[] floatArray = new float[BUFFER_SIZE_IN_BYTES / 4]; 389 capturedAudio = new AudioHelper.CapturedAudio(audioCapture, floatArray, readMode); 390 float roundOffError = Math.abs(capturedAudio.getFloatValue() - FLOAT_VALUE); 391 assertThat(roundOffError).isLessThan(0.001f); 392 break; 393 } 394 395 verify(mActivityResultCallback, timeout(5000)).onActivityResult( 396 mIntentCaptor.capture()); 397 activityResultReceiver.unregister(); 398 } 399 runAudioInjectionTest(@udioHelper.DataType int dataType, int writeMode, long timestamp)400 private void runAudioInjectionTest(@AudioHelper.DataType int dataType, int writeMode, 401 long timestamp) { 402 mVirtualAudioDevice = mVirtualDevice.createVirtualAudioDevice( 403 mVirtualDisplay, /* executor= */ null, /* callback= */ null); 404 int encoding = dataType == FLOAT_ARRAY ? ENCODING_PCM_FLOAT : ENCODING_PCM_16BIT; 405 AudioInjection audioInjection = mVirtualAudioDevice.startAudioInjection( 406 createInjectionFormat(encoding)); 407 408 ActivityResultReceiver activityResultReceiver = new ActivityResultReceiver( 409 getApplicationContext()); 410 activityResultReceiver.register(mActivityResultCallback); 411 InstrumentationRegistry.getInstrumentation().getTargetContext().startActivity( 412 createAudioRecordIntent(dataType), 413 createActivityOptions(mVirtualDisplay)); 414 415 int remaining; 416 switch (dataType) { 417 case BYTE_BUFFER: 418 ByteBuffer byteBuffer = AudioHelper.createAudioData( 419 SAMPLE_RATE, NUMBER_OF_SAMPLES, CHANNEL_COUNT, FREQUENCY, AMPLITUDE); 420 remaining = byteBuffer.remaining(); 421 while (remaining > 0) { 422 if (timestamp != 0) { 423 remaining -= audioInjection.write(byteBuffer, byteBuffer.remaining(), 424 writeMode, timestamp); 425 } else { 426 remaining -= audioInjection.write(byteBuffer, byteBuffer.remaining(), 427 writeMode); 428 } 429 } 430 break; 431 case BYTE_ARRAY: 432 byte[] byteArray = new byte[NUMBER_OF_SAMPLES]; 433 for (int i = 0; i < byteArray.length; i++) { 434 byteArray[i] = BYTE_VALUE; 435 } 436 remaining = byteArray.length; 437 while (remaining > 0) { 438 if (writeMode == WRITE_BLOCKING || writeMode == WRITE_NON_BLOCKING) { 439 remaining -= audioInjection.write(byteArray, 0, byteArray.length, 440 writeMode); 441 } else { 442 remaining -= audioInjection.write(byteArray, 0, byteArray.length); 443 } 444 } 445 break; 446 case SHORT_ARRAY: 447 short[] shortArray = new short[NUMBER_OF_SAMPLES]; 448 for (int i = 0; i < shortArray.length; i++) { 449 shortArray[i] = SHORT_VALUE; 450 } 451 remaining = shortArray.length; 452 while (remaining > 0) { 453 if (writeMode == WRITE_BLOCKING || writeMode == WRITE_NON_BLOCKING) { 454 remaining -= audioInjection.write(shortArray, 0, shortArray.length, 455 writeMode); 456 } else { 457 remaining -= audioInjection.write(shortArray, 0, shortArray.length); 458 } 459 } 460 break; 461 case FLOAT_ARRAY: 462 float[] floatArray = new float[NUMBER_OF_SAMPLES]; 463 for (int i = 0; i < floatArray.length; i++) { 464 floatArray[i] = FLOAT_VALUE; 465 } 466 remaining = floatArray.length; 467 while (remaining > 0) { 468 remaining -= audioInjection.write(floatArray, 0, floatArray.length, writeMode); 469 } 470 break; 471 } 472 473 verify(mActivityResultCallback, timeout(5000)).onActivityResult( 474 mIntentCaptor.capture()); 475 Intent intent = mIntentCaptor.getValue(); 476 assertThat(intent).isNotNull(); 477 activityResultReceiver.unregister(); 478 479 switch (dataType) { 480 case BYTE_BUFFER: 481 double powerSpectrumAtFrequency = intent.getDoubleExtra( 482 EXTRA_POWER_SPECTRUM_AT_FREQUENCY, 483 0); 484 double powerSpectrumNotFrequency = intent.getDoubleExtra( 485 EXTRA_POWER_SPECTRUM_NOT_FREQUENCY, 486 0); 487 assertThat(powerSpectrumNotFrequency).isLessThan(POWER_THRESHOLD_FOR_ABSENT); 488 assertThat(powerSpectrumAtFrequency).isGreaterThan(POWER_THRESHOLD_FOR_PRESENT); 489 break; 490 case BYTE_ARRAY: 491 byte byteValue = intent.getByteExtra(EXTRA_LAST_RECORDED_NONZERO_VALUE, 492 Byte.MIN_VALUE); 493 assertThat(byteValue).isEqualTo(BYTE_VALUE); 494 break; 495 case SHORT_ARRAY: 496 short shortValue = intent.getShortExtra(EXTRA_LAST_RECORDED_NONZERO_VALUE, 497 Short.MIN_VALUE); 498 assertThat(shortValue).isEqualTo(SHORT_VALUE); 499 break; 500 case FLOAT_ARRAY: 501 float floatValue = intent.getFloatExtra(EXTRA_LAST_RECORDED_NONZERO_VALUE, 0); 502 float roundOffError = Math.abs(floatValue - FLOAT_VALUE); 503 assertThat(roundOffError).isLessThan(0.001f); 504 break; 505 } 506 } 507 createCaptureFormat(int encoding)508 private static AudioFormat createCaptureFormat(int encoding) { 509 return new AudioFormat.Builder() 510 .setSampleRate(SAMPLE_RATE) 511 .setEncoding(encoding) 512 .setChannelMask(CHANNEL_IN_MONO) 513 .build(); 514 } 515 createInjectionFormat(int encoding)516 private static AudioFormat createInjectionFormat(int encoding) { 517 return new AudioFormat.Builder() 518 .setSampleRate(SAMPLE_RATE) 519 .setEncoding(encoding) 520 .setChannelMask(CHANNEL_IN_MONO) 521 .build(); 522 } 523 createPlayAudioIntent(@udioHelper.DataType int dataType)524 private static Intent createPlayAudioIntent(@AudioHelper.DataType int dataType) { 525 return new Intent(ACTION_PLAY_AUDIO) 526 .putExtra(EXTRA_AUDIO_DATA_TYPE, dataType) 527 .setComponent(MAIN_ACTIVITY_COMPONENT) 528 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 529 } 530 createAudioRecordIntent(@udioHelper.DataType int dataType)531 private static Intent createAudioRecordIntent(@AudioHelper.DataType int dataType) { 532 return new Intent(ACTION_RECORD_AUDIO) 533 .putExtra(EXTRA_AUDIO_DATA_TYPE, dataType) 534 .setComponent(MAIN_ACTIVITY_COMPONENT) 535 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 536 } 537 } 538