CarAudioFocusSystemSoundTest.java revision 0d07c76bbc788fba8c77d8e932330ab22ec6ba27
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 */ 16package com.android.car.test; 17 18import static android.hardware.vehicle.V2_0.VehicleProperty.AUDIO_FOCUS; 19 20import android.car.Car; 21import android.car.media.CarAudioManager; 22import android.content.Context; 23import android.hardware.vehicle.V2_0.VehicleAudioContextFlag; 24import android.hardware.vehicle.V2_0.VehicleAudioExtFocusFlag; 25import android.hardware.vehicle.V2_0.VehicleAudioFocusIndex; 26import android.hardware.vehicle.V2_0.VehicleAudioFocusRequest; 27import android.hardware.vehicle.V2_0.VehicleAudioFocusState; 28import android.hardware.vehicle.V2_0.VehicleAudioStream; 29import android.hardware.vehicle.V2_0.VehiclePropValue; 30import android.hardware.vehicle.V2_0.VehicleProperty; 31import android.hardware.vehicle.V2_0.VehiclePropertyAccess; 32import android.media.AudioAttributes; 33import android.media.AudioManager; 34import android.os.SystemClock; 35import android.test.suitebuilder.annotation.MediumTest; 36 37import com.google.android.collect.Lists; 38 39import com.android.car.vehiclehal.test.MockedVehicleHal.FailingPropertyHandler; 40import com.android.car.vehiclehal.test.MockedVehicleHal.VehicleHalPropertyHandler; 41import com.android.car.vehiclehal.VehiclePropValueBuilder; 42 43import java.util.ArrayList; 44import java.util.concurrent.Semaphore; 45import java.util.concurrent.TimeUnit; 46 47/** 48 * Test to check if system sound can be played without having focus. 49 */ 50@MediumTest 51public class CarAudioFocusSystemSoundTest extends MockedCarTestBase { 52 private static final String TAG = CarAudioFocusTest.class.getSimpleName(); 53 54 private static final long TIMEOUT_MS = 3000; 55 56 private final VehicleHalPropertyHandler mAudioRoutingPolicyPropertyHandler = 57 new FailingPropertyHandler() { 58 @Override 59 public void onPropertySet(VehiclePropValue value) { 60 //TODO 61 } 62 }; 63 64 private final FocusPropertyHandler mAudioFocusPropertyHandler = 65 new FocusPropertyHandler(this); 66 67 private AudioManager mAudioManager; 68 69 @Override 70 protected synchronized void configureMockedHal() { 71 addProperty(VehicleProperty.AUDIO_ROUTING_POLICY, mAudioRoutingPolicyPropertyHandler) 72 .setAccess(VehiclePropertyAccess.WRITE); 73 addProperty(VehicleProperty.AUDIO_FOCUS, mAudioFocusPropertyHandler); 74 75 addStaticProperty(VehicleProperty.AUDIO_HW_VARIANT, 76 VehiclePropValueBuilder.newBuilder(VehicleProperty.AUDIO_HW_VARIANT) 77 .addIntValue(-1) 78 .build()) 79 .setConfigArray(Lists.newArrayList(0)); 80 } 81 82 @Override 83 protected void setUp() throws Exception { 84 super.setUp(); 85 // AudioManager should be created in main thread to get focus event. :( 86 runOnMainSync(new Runnable() { 87 @Override 88 public void run() { 89 mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); 90 } 91 }); 92 } 93 94 private void notifyStreamState(int streamNumber, boolean active) { 95 int[] values = { active ? 1 : 0, streamNumber }; 96 long now = SystemClock.elapsedRealtimeNanos(); 97 // TODO(pavelm): we don't have internal properties anymore. 98// getMockedVehicleHal().injectEvent(VehiclePropValueUtil.createIntVectorValue( 99// INTERNAL_AUDIO_STREAM_STATE, values, now)); 100 } 101 102 public void testSystemSoundPlayStop() throws Exception { 103 //system sound start 104 notifyStreamState(1, true); 105 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 106 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_NO_DUCK, 107 request[0]); 108 assertEquals(0x2, request[1]); 109 assertEquals(0, request[2]); 110 assertEquals(VehicleAudioContextFlag.SYSTEM_SOUND_FLAG, request[3]); 111 mAudioFocusPropertyHandler.sendAudioFocusState( 112 VehicleAudioFocusState.STATE_GAIN_TRANSIENT, 113 request[1], 114 VehicleAudioExtFocusFlag.NONE_FLAG); 115 // system sound stop 116 notifyStreamState(1, false); 117 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 118 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, 119 request[0]); 120 assertEquals(0, request[1]); 121 assertEquals(0, request[2]); 122 assertEquals(0, request[3]); 123 mAudioFocusPropertyHandler.sendAudioFocusState( 124 VehicleAudioFocusState.STATE_LOSS, 125 request[1], 126 VehicleAudioExtFocusFlag.NONE_FLAG); 127 } 128 129 public void testRadioSystemSound() throws Exception { 130 // radio start 131 AudioFocusListener listenerRadio = new AudioFocusListener(); 132 CarAudioManager carAudioManager = (CarAudioManager) getCar().getCarManager( 133 Car.AUDIO_SERVICE); 134 assertNotNull(carAudioManager); 135 AudioAttributes radioAttributes = carAudioManager.getAudioAttributesForCarUsage( 136 CarAudioManager.CAR_AUDIO_USAGE_RADIO); 137 int res = mAudioManager.requestAudioFocus(listenerRadio, 138 radioAttributes, AudioManager.AUDIOFOCUS_GAIN, 0); 139 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 140 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 141 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 142 assertEquals(0, request[1]); 143 assertEquals(VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG, 144 request[2]); 145 assertEquals(VehicleAudioContextFlag.RADIO_FLAG, request[3]); 146 mAudioFocusPropertyHandler.sendAudioFocusState( 147 VehicleAudioFocusState.STATE_GAIN, 148 0, 149 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG); 150 // system sound start 151 notifyStreamState(1, true); 152 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 153 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 154 assertEquals(0x2, request[1]); 155 assertEquals(VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG, 156 request[2]); 157 assertEquals(VehicleAudioContextFlag.RADIO_FLAG | 158 VehicleAudioContextFlag.SYSTEM_SOUND_FLAG, request[3]); 159 mAudioFocusPropertyHandler.sendAudioFocusState( 160 VehicleAudioFocusState.STATE_GAIN, 161 request[1], 162 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG); 163 // system sound stop 164 notifyStreamState(1, false); 165 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 166 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 167 assertEquals(0, request[1]); 168 assertEquals(VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG, 169 request[2]); 170 assertEquals(VehicleAudioContextFlag.RADIO_FLAG, request[3]); 171 mAudioFocusPropertyHandler.sendAudioFocusState( 172 VehicleAudioFocusState.STATE_GAIN, 173 0, 174 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG); 175 // radio stop 176 mAudioManager.abandonAudioFocus(listenerRadio); 177 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 178 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, request[0]); 179 assertEquals(0, request[1]); 180 assertEquals(0, request[2]); 181 assertEquals(0, request[3]); 182 mAudioFocusPropertyHandler.sendAudioFocusState( 183 VehicleAudioFocusState.STATE_LOSS, 184 request[1], 185 VehicleAudioExtFocusFlag.NONE_FLAG); 186 } 187 188 public void testMusicSystemSound() throws Exception { 189 // music start 190 AudioFocusListener listenerMusic = new AudioFocusListener(); 191 int res = mAudioManager.requestAudioFocus(listenerMusic, 192 AudioManager.STREAM_MUSIC, 193 AudioManager.AUDIOFOCUS_GAIN); 194 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 195 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 196 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 197 assertEquals(0x1 << VehicleAudioStream.STREAM0, request[1]); 198 assertEquals(0, request[2]); 199 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG, request[3]); 200 mAudioFocusPropertyHandler.sendAudioFocusState( 201 VehicleAudioFocusState.STATE_GAIN, 202 request[1], 203 VehicleAudioExtFocusFlag.NONE_FLAG); 204 // system sound start 205 notifyStreamState(1, true); 206 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 207 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 208 assertEquals(0x1 | 0x2, request[1]); 209 assertEquals(0, request[2]); 210 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG | 211 VehicleAudioContextFlag.SYSTEM_SOUND_FLAG, request[3]); 212 mAudioFocusPropertyHandler.sendAudioFocusState( 213 VehicleAudioFocusState.STATE_GAIN, 214 request[1], 215 VehicleAudioExtFocusFlag.NONE_FLAG); 216 // system sound stop 217 notifyStreamState(1, false); 218 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 219 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN, request[0]); 220 assertEquals(0x1 << VehicleAudioStream.STREAM0, request[1]); 221 assertEquals(0, request[2]); 222 assertEquals(VehicleAudioContextFlag.MUSIC_FLAG, request[3]); 223 mAudioFocusPropertyHandler.sendAudioFocusState( 224 VehicleAudioFocusState.STATE_GAIN, 225 request[1], 226 VehicleAudioExtFocusFlag.NONE_FLAG); 227 // music stop 228 mAudioManager.abandonAudioFocus(listenerMusic); 229 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 230 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, request[0]); 231 assertEquals(0, request[1]); 232 assertEquals(0, request[2]); 233 assertEquals(0, request[3]); 234 mAudioFocusPropertyHandler.sendAudioFocusState( 235 VehicleAudioFocusState.STATE_LOSS, 236 request[1], 237 VehicleAudioExtFocusFlag.NONE_FLAG); 238 } 239 240 public void testNavigationSystemSound() throws Exception { 241 // nav guidance start 242 AudioFocusListener listenerNav = new AudioFocusListener(); 243 AudioAttributes navAttrib = (new AudioAttributes.Builder()). 244 setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION). 245 setUsage(AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE). 246 build(); 247 int res = mAudioManager.requestAudioFocus(listenerNav, navAttrib, 248 AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK, 0); 249 assertEquals(AudioManager.AUDIOFOCUS_REQUEST_GRANTED, res); 250 int[] request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 251 assertEquals(VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_MAY_DUCK, 252 request[0]); 253 assertEquals(0x2, request[1]); 254 assertEquals(0, request[2]); 255 assertEquals(VehicleAudioContextFlag.NAVIGATION_FLAG, request[3]); 256 mAudioFocusPropertyHandler.sendAudioFocusState( 257 VehicleAudioFocusState.STATE_GAIN_TRANSIENT, 258 request[1], 259 VehicleAudioExtFocusFlag.NONE_FLAG); 260 // system sound start 261 notifyStreamState(1, true); 262 // cannot distinguish this case from nav only. so no focus change. 263 mAudioFocusPropertyHandler.assertNoFocusRequest(1000); 264 // cannot distinguish this case from nav only. so no focus change. 265 notifyStreamState(1, false); 266 mAudioFocusPropertyHandler.assertNoFocusRequest(1000); 267 // nav guidance stop 268 mAudioManager.abandonAudioFocus(listenerNav); 269 request = mAudioFocusPropertyHandler.waitForAudioFocusRequest(TIMEOUT_MS); 270 assertEquals(VehicleAudioFocusRequest.REQUEST_RELEASE, request[0]); 271 assertEquals(0, request[1]); 272 assertEquals(0, request[2]); 273 assertEquals(0, request[3]); 274 mAudioFocusPropertyHandler.sendAudioFocusState( 275 VehicleAudioFocusState.STATE_LOSS, 276 request[1], 277 VehicleAudioExtFocusFlag.NONE_FLAG); 278 } 279 280 private static class AudioFocusListener implements AudioManager.OnAudioFocusChangeListener { 281 private final Semaphore mFocusChangeWait = new Semaphore(0); 282 private int mLastFocusChange; 283 284 // TODO: not used? 285 public int waitAndGetFocusChange(long timeoutMs) throws Exception { 286 if (!mFocusChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 287 fail("timeout waiting for focus change"); 288 } 289 return mLastFocusChange; 290 } 291 292 public void waitForFocus(long timeoutMs, int expectedFocus) throws Exception { 293 while (mLastFocusChange != expectedFocus) { 294 if (!mFocusChangeWait.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 295 fail("timeout waiting for focus change"); 296 } 297 } 298 } 299 300 @Override 301 public void onAudioFocusChange(int focusChange) { 302 mLastFocusChange = focusChange; 303 mFocusChangeWait.release(); 304 } 305 } 306 307 private static class FocusPropertyHandler implements VehicleHalPropertyHandler { 308 309 private int mState = VehicleAudioFocusState.STATE_LOSS; 310 private int mStreams = 0; 311 private int mExtFocus = 0; 312 private int mRequest; 313 private int mRequestedStreams; 314 private int mRequestedExtFocus; 315 private int mRequestedAudioContexts; 316 private final MockedCarTestBase mCarTest; 317 318 private final Semaphore mSetWaitSemaphore = new Semaphore(0); 319 320 FocusPropertyHandler(MockedCarTestBase carTest) { 321 mCarTest = carTest; 322 } 323 324 void sendAudioFocusState(int state, int streams, int extFocus) { 325 synchronized (this) { 326 mState = state; 327 mStreams = streams; 328 mExtFocus = extFocus; 329 } 330 mCarTest.getMockedVehicleHal().injectEvent( 331 VehiclePropValueBuilder.newBuilder(AUDIO_FOCUS) 332 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 333 .addIntValue(state, streams, extFocus, 0) 334 .build()); 335 } 336 337 int[] waitForAudioFocusRequest(long timeoutMs) throws Exception { 338 if (!mSetWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 339 fail("timeout"); 340 } 341 synchronized (this) { 342 return new int[] { mRequest, mRequestedStreams, mRequestedExtFocus, 343 mRequestedAudioContexts }; 344 } 345 } 346 347 void assertNoFocusRequest(long timeoutMs) throws Exception { 348 if (mSetWaitSemaphore.tryAcquire(timeoutMs, TimeUnit.MILLISECONDS)) { 349 fail("should not get focus request"); 350 } 351 } 352 353 @Override 354 public void onPropertySet(VehiclePropValue value) { 355 assertEquals(AUDIO_FOCUS, value.prop); 356 ArrayList<Integer> v = value.value.int32Values; 357 synchronized (this) { 358 mRequest = v.get(VehicleAudioFocusIndex.FOCUS); 359 mRequestedStreams = v.get(VehicleAudioFocusIndex.STREAMS); 360 mRequestedExtFocus = v.get(VehicleAudioFocusIndex.EXTERNAL_FOCUS_STATE); 361 mRequestedAudioContexts = v.get(VehicleAudioFocusIndex.AUDIO_CONTEXTS); 362 } 363 mSetWaitSemaphore.release(); 364 } 365 366 @Override 367 public VehiclePropValue onPropertyGet(VehiclePropValue value) { 368 assertEquals(VehicleProperty.AUDIO_FOCUS, value.prop); 369 int state, streams, extFocus; 370 synchronized (this) { 371 state = mState; 372 streams = mStreams; 373 extFocus = mExtFocus; 374 } 375 return VehiclePropValueBuilder.newBuilder(AUDIO_FOCUS) 376 .setTimestamp(SystemClock.elapsedRealtimeNanos()) 377 .addIntValue(state, streams, extFocus, 0) 378 .build(); 379 } 380 381 @Override 382 public void onPropertySubscribe(int property, int zones, float sampleRate) { 383 assertEquals(VehicleProperty.AUDIO_FOCUS, property); 384 } 385 386 @Override 387 public void onPropertyUnsubscribe(int property) { 388 assertEquals(VehicleProperty.AUDIO_FOCUS, property); 389 } 390 } 391} 392