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