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