blob: beb9e845af4809c397173578fde5220f54db3251 [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.media.cts;
import static org.testng.Assert.assertThrows;
import android.annotation.NonNull;
import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.Spatializer;
import android.util.Log;
import com.android.compatibility.common.util.CtsAndroidTestCase;
import com.android.internal.annotations.GuardedBy;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
@NonMediaMainlineTest
public class SpatializerTest extends CtsAndroidTestCase {
private AudioManager mAudioManager;
private static final String TAG = "SpatializerTest";
@Override
protected void setUp() throws Exception {
super.setUp();
mAudioManager = (AudioManager) getContext().getSystemService(AudioManager.class);
}
public void testGetSpatializer() {
Spatializer spat = mAudioManager.getSpatializer();
assertNotNull("Spatializer shouldn't be null", spat);
}
public void testMinSpatializationCapabilities() {
Spatializer spat = mAudioManager.getSpatializer();
if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) {
Log.i(TAG, "skipping testMinSpatializationCapabilities, no Spatializer");
return;
}
if (!spat.isAvailable()) {
Log.i(TAG, "skipping testMinSpatializationCapabilities, Spatializer not available");
return;
}
for (int sampleRate : new int[] { 44100, 4800 }) {
AudioFormat minFormat = new AudioFormat.Builder()
.setSampleRate(sampleRate)
.setChannelMask(AudioFormat.CHANNEL_OUT_5POINT1)
.setEncoding(AudioFormat.ENCODING_PCM_16BIT)
.build();
for (int usage : new int[] { AudioAttributes.USAGE_MEDIA,
AudioAttributes.USAGE_GAME}) {
AudioAttributes defAttr = new AudioAttributes.Builder()
.setUsage(usage)
.build();
assertTrue("AudioAttributes usage:" + usage + " at " + sampleRate
+ " should be virtualizeable", spat.canBeSpatialized(defAttr, minFormat));
}
}
}
public void testVirtualizerEnabled() throws Exception {
Spatializer spat = mAudioManager.getSpatializer();
if (spat.getImmersiveAudioLevel() == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) {
Log.i(TAG, "skipping testVirtualizerEnabled, no Spatializer");
return;
}
boolean spatEnabled = spat.isEnabled();
final MySpatStateListener stateListener = new MySpatStateListener();
spat.addOnSpatializerStateChangedListener(Executors.newSingleThreadExecutor(),
stateListener);
getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
spat.setEnabled(!spatEnabled);
getInstrumentation().getUiAutomation()
.dropShellPermissionIdentity();
assertEquals("VirtualizerStage enabled state differ",
!spatEnabled, spat.isEnabled());
Boolean enabled = stateListener.getEnabled();
assertNotNull("VirtualizerStage state listener wasn't called", enabled);
assertEquals("VirtualizerStage state listener didn't get expected value",
!spatEnabled, enabled.booleanValue());
}
static class MySpatStateListener
implements Spatializer.OnSpatializerStateChangedListener {
private final Object mCbEnaLock = new Object();
private final Object mCbAvailLock = new Object();
@GuardedBy("mCbEnaLock")
private Boolean mEnabled = null;
@GuardedBy("mCbEnaLock")
private final LinkedBlockingQueue<Boolean> mEnabledQueue =
new LinkedBlockingQueue<Boolean>();
@GuardedBy("mCbAvailLock")
private Boolean mAvailable = null;
@GuardedBy("mCbAvailLock")
private final LinkedBlockingQueue<Boolean> mAvailableQueue =
new LinkedBlockingQueue<Boolean>();
private static final int LISTENER_WAIT_TIMEOUT_MS = 3000;
void reset() {
synchronized (mCbEnaLock) {
synchronized (mCbAvailLock) {
mEnabled = null;
mEnabledQueue.clear();
mAvailable = null;
mAvailableQueue.clear();
}
}
}
Boolean getEnabled() {
synchronized (mCbEnaLock) {
while (mEnabled == null) {
try {
mEnabled = mEnabledQueue.poll(
LISTENER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (mEnabled == null) { // timeout
break;
}
} catch (InterruptedException e) {
}
}
}
return mEnabled;
}
Boolean getAvailable() {
synchronized (mCbAvailLock) {
while (mAvailable == null) {
try {
mAvailable = mAvailableQueue.poll(
LISTENER_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS);
if (mAvailable == null) { // timeout
break;
}
} catch (InterruptedException e) {
}
}
}
return mAvailable;
}
MySpatStateListener() {
reset();
}
@Override
public void onSpatializerEnabledChanged(Spatializer spat, boolean enabled) {
synchronized (mCbEnaLock) {
try {
mEnabledQueue.put(enabled);
} catch (InterruptedException e) {
fail("Failed to put enabled event in queue");
}
}
}
@Override
public void onSpatializerAvailableChanged(@NonNull Spatializer spat, boolean available) {
synchronized (mCbAvailLock) {
try {
mAvailableQueue.put(available);
} catch (InterruptedException e) {
fail("Failed to put available event in queue");
}
}
}
}
}