Merge "AudioPolicyDeathTest: fix flakiness"
This commit is contained in:
@@ -2,4 +2,7 @@
|
||||
<resources>
|
||||
<!-- name of the app [CHAR LIMIT=25]-->
|
||||
<string name="app_name">Audio Policy APIs Tests</string>
|
||||
<string name="capture_duration_key">captureDurationMs</string>
|
||||
<string name="callback_key">callback</string>
|
||||
<string name="status_key">result</string>
|
||||
</resources>
|
||||
|
||||
@@ -20,6 +20,8 @@ import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assume.assumeNoException;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
@@ -30,6 +32,8 @@ import android.media.AudioAttributes;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioTrack;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteCallback;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -39,33 +43,62 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
@Presubmit
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class AudioPolicyDeathTest {
|
||||
private static final String TAG = "AudioPolicyDeathTest";
|
||||
|
||||
private static final int SAMPLE_RATE = 48000;
|
||||
private static final int PLAYBACK_TIME_MS = 2000;
|
||||
private static final int PLAYBACK_TIME_MS = 4000;
|
||||
private static final int RECORD_TIME_MS = 1000;
|
||||
private static final int ACTIVITY_TIMEOUT_SEC = 5;
|
||||
private static final int BROADCAST_TIMEOUT_SEC = 10;
|
||||
private static final int MAX_ATTEMPTS = 5;
|
||||
private static final int DELAY_BETWEEN_ATTEMPTS_MS = 2000;
|
||||
|
||||
private static final IntentFilter AUDIO_NOISY_INTENT_FILTER =
|
||||
new IntentFilter(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
|
||||
|
||||
private class MyBroadcastReceiver extends BroadcastReceiver {
|
||||
private boolean mReceived = false;
|
||||
private CountDownLatch mLatch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (AudioManager.ACTION_AUDIO_BECOMING_NOISY.equals(intent.getAction())) {
|
||||
synchronized (this) {
|
||||
mReceived = true;
|
||||
notify();
|
||||
}
|
||||
mLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized boolean received() {
|
||||
return mReceived;
|
||||
public void reset() {
|
||||
mLatch = new CountDownLatch(1);
|
||||
}
|
||||
|
||||
public boolean waitForBroadcast() {
|
||||
boolean received = false;
|
||||
long startTimeMs = System.currentTimeMillis();
|
||||
long elapsedTimeMs = 0;
|
||||
|
||||
Log.i(TAG, "waiting for broadcast");
|
||||
|
||||
while (elapsedTimeMs < BROADCAST_TIMEOUT_SEC && !received) {
|
||||
try {
|
||||
received = mLatch.await(BROADCAST_TIMEOUT_SEC, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(TAG, "wait interrupted");
|
||||
}
|
||||
elapsedTimeMs = System.currentTimeMillis() - startTimeMs;
|
||||
}
|
||||
Log.i(TAG, "broadcast " + (received ? "" : "NOT ") + "received");
|
||||
return received;
|
||||
}
|
||||
}
|
||||
|
||||
private final MyBroadcastReceiver mReceiver = new MyBroadcastReceiver();
|
||||
|
||||
private Context mContext;
|
||||
@@ -85,31 +118,55 @@ public class AudioPolicyDeathTest {
|
||||
public void testPolicyClientDeathSendBecomingNoisyIntent() {
|
||||
mContext.registerReceiver(mReceiver, AUDIO_NOISY_INTENT_FILTER);
|
||||
|
||||
// Launch process registering a dynamic auido policy and dying after PLAYBACK_TIME_MS/2 ms
|
||||
Intent intent = new Intent(mContext, AudioPolicyDeathTestActivity.class);
|
||||
intent.putExtra("captureDurationMs", PLAYBACK_TIME_MS / 2);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
mContext.startActivity(intent);
|
||||
boolean result = false;
|
||||
for (int numAttempts = 1; numAttempts <= MAX_ATTEMPTS && !result; numAttempts++) {
|
||||
mReceiver.reset();
|
||||
|
||||
AudioTrack track = createAudioTrack();
|
||||
track.play();
|
||||
synchronized (mReceiver) {
|
||||
long startTimeMs = System.currentTimeMillis();
|
||||
long elapsedTimeMs = 0;
|
||||
while (elapsedTimeMs < PLAYBACK_TIME_MS && !mReceiver.received()) {
|
||||
try {
|
||||
mReceiver.wait(PLAYBACK_TIME_MS - elapsedTimeMs);
|
||||
} catch (InterruptedException e) {
|
||||
Log.w(TAG, "wait interrupted");
|
||||
CompletableFuture<Integer> callbackReturn = new CompletableFuture<>();
|
||||
RemoteCallback cb = new RemoteCallback((Bundle res) -> {
|
||||
callbackReturn.complete(
|
||||
res.getInt(mContext.getResources().getString(R.string.status_key)));
|
||||
});
|
||||
|
||||
// Launch process registering a dynamic auido policy and dying after RECORD_TIME_MS ms
|
||||
// RECORD_TIME_MS must be shorter than PLAYBACK_TIME_MS
|
||||
Intent intent = new Intent(mContext, AudioPolicyDeathTestActivity.class);
|
||||
intent.putExtra(mContext.getResources().getString(R.string.capture_duration_key),
|
||||
RECORD_TIME_MS);
|
||||
intent.putExtra(mContext.getResources().getString(R.string.callback_key), cb);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
|
||||
|
||||
mContext.startActivity(intent);
|
||||
|
||||
Integer status = AudioManager.ERROR;
|
||||
try {
|
||||
status = callbackReturn.get(ACTIVITY_TIMEOUT_SEC, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
assumeNoException(e);
|
||||
}
|
||||
assumeTrue(status != null && status == AudioManager.SUCCESS);
|
||||
|
||||
Log.i(TAG, "Activity started");
|
||||
AudioTrack track = null;
|
||||
try {
|
||||
track = createAudioTrack();
|
||||
track.play();
|
||||
result = mReceiver.waitForBroadcast();
|
||||
} finally {
|
||||
if (track != null) {
|
||||
track.stop();
|
||||
track.release();
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
try {
|
||||
Log.i(TAG, "Retrying after attempt: " + numAttempts);
|
||||
Thread.sleep(DELAY_BETWEEN_ATTEMPTS_MS);
|
||||
} catch (InterruptedException e) {
|
||||
}
|
||||
elapsedTimeMs = System.currentTimeMillis() - startTimeMs;
|
||||
}
|
||||
}
|
||||
|
||||
track.stop();
|
||||
track.release();
|
||||
|
||||
assertTrue(mReceiver.received());
|
||||
assertTrue(result);
|
||||
}
|
||||
|
||||
private AudioTrack createAudioTrack() {
|
||||
|
||||
@@ -26,6 +26,7 @@ import android.media.audiopolicy.AudioMixingRule;
|
||||
import android.media.audiopolicy.AudioPolicy;
|
||||
import android.os.Bundle;
|
||||
import android.os.Looper;
|
||||
import android.os.RemoteCallback;
|
||||
import android.util.Log;
|
||||
|
||||
// This activity will register a dynamic audio policy to intercept media playback and launch
|
||||
@@ -71,19 +72,29 @@ public class AudioPolicyDeathTestActivity extends Activity {
|
||||
mAudioPolicy = audioPolicyBuilder.build();
|
||||
|
||||
int result = mAudioManager.registerAudioPolicy(mAudioPolicy);
|
||||
if (result != AudioManager.SUCCESS) {
|
||||
if (result == AudioManager.SUCCESS) {
|
||||
AudioRecord audioRecord = mAudioPolicy.createAudioRecordSink(audioMix);
|
||||
if (audioRecord != null && audioRecord.getState() != AudioRecord.STATE_UNINITIALIZED) {
|
||||
int captureDurationMs = getIntent().getIntExtra(
|
||||
getString(R.string.capture_duration_key), RECORD_TIME_MS);
|
||||
AudioCapturingThread thread =
|
||||
new AudioCapturingThread(audioRecord, captureDurationMs);
|
||||
thread.start();
|
||||
} else {
|
||||
Log.w(TAG, "AudioRecord creation failed");
|
||||
result = AudioManager.ERROR_NO_INIT;
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "registerAudioPolicy failed, status: " + result);
|
||||
return;
|
||||
}
|
||||
AudioRecord audioRecord = mAudioPolicy.createAudioRecordSink(audioMix);
|
||||
if (audioRecord == null) {
|
||||
Log.w(TAG, "AudioRecord creation failed");
|
||||
return;
|
||||
}
|
||||
|
||||
int captureDurationMs = getIntent().getIntExtra("captureDurationMs", RECORD_TIME_MS);
|
||||
AudioCapturingThread thread = new AudioCapturingThread(audioRecord, captureDurationMs);
|
||||
thread.start();
|
||||
RemoteCallback cb =
|
||||
(RemoteCallback) getIntent().getExtras().get(getString(R.string.callback_key));
|
||||
Bundle res = new Bundle();
|
||||
res.putInt(getString(R.string.status_key), result);
|
||||
Log.i(TAG, "policy " + (result == AudioManager.SUCCESS ? "" : "un")
|
||||
+ "successfully registered");
|
||||
cb.sendResult(res);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user