Home | History | Annotate | Download | only in hal
      1 /*
      2  * Copyright (C) 2015 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.hal;
     17 
     18 import android.car.media.CarAudioManager;
     19 import android.os.ServiceSpecificException;
     20 import android.util.Log;
     21 
     22 import com.android.car.AudioRoutingPolicy;
     23 import com.android.car.CarAudioAttributesUtil;
     24 import com.android.car.CarLog;
     25 import com.android.car.vehiclenetwork.VehicleNetwork;
     26 import com.android.car.vehiclenetwork.VehicleNetworkConsts;
     27 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioContextFlag;
     28 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioExtFocusFlag;
     29 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusIndex;
     30 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequest;
     31 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState;
     32 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioHwVariantConfigFlag;
     33 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioRoutingPolicyIndex;
     34 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamState;
     35 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamStateIndex;
     36 import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioVolumeIndex;
     37 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
     38 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
     39 import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
     40 
     41 import java.io.PrintWriter;
     42 import java.util.HashMap;
     43 import java.util.LinkedList;
     44 import java.util.List;
     45 
     46 public class AudioHalService extends HalServiceBase {
     47 
     48     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_INVALID = -1;
     49     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN =
     50             VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
     51     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT =
     52             VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
     53     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK =
     54             VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
     55     public static final int VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE =
     56             VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
     57 
     58     public static String audioFocusRequestToString(int request) {
     59         return VehicleAudioFocusRequest.enumToString(request);
     60     }
     61 
     62     public static final int VEHICLE_AUDIO_FOCUS_STATE_INVALID = -1;
     63     public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN =
     64             VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
     65     public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT =
     66             VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
     67     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK =
     68             VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
     69     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT =
     70             VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
     71     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS =
     72             VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
     73     public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE =
     74             VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
     75 
     76     public static String audioFocusStateToString(int state) {
     77         return VehicleAudioFocusState.enumToString(state);
     78     }
     79 
     80     public static final int VEHICLE_AUDIO_STREAM_STATE_STOPPED =
     81             VehicleAudioStreamState.VEHICLE_AUDIO_STREAM_STATE_STOPPED;
     82     public static final int VEHICLE_AUDIO_STREAM_STATE_STARTED =
     83             VehicleAudioStreamState.VEHICLE_AUDIO_STREAM_STATE_STARTED;
     84 
     85     public static String audioStreamStateToString(int state) {
     86         return VehicleAudioStreamState.enumToString(state);
     87     }
     88 
     89     public static final int VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG =
     90             VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG;
     91     public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG =
     92             VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG;
     93     public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT_FLAG =
     94             VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT_FLAG;
     95     public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG =
     96             VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG;
     97 
     98     public static final int STREAM_NUM_DEFAULT = 0;
     99 
    100     public static final int FOCUS_STATE_ARRAY_INDEX_STATE = 0;
    101     public static final int FOCUS_STATE_ARRAY_INDEX_STREAMS = 1;
    102     public static final int FOCUS_STATE_ARRAY_INDEX_EXTERNAL_FOCUS = 2;
    103 
    104     public static final int AUDIO_CONTEXT_MUSIC_FLAG =
    105             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG;
    106     public static final int AUDIO_CONTEXT_NAVIGATION_FLAG =
    107             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG;
    108     public static final int AUDIO_CONTEXT_VOICE_COMMAND_FLAG =
    109             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_VOICE_COMMAND_FLAG;
    110     public static final int AUDIO_CONTEXT_CALL_FLAG =
    111             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CALL_FLAG;
    112     public static final int AUDIO_CONTEXT_ALARM_FLAG =
    113             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_ALARM_FLAG;
    114     public static final int AUDIO_CONTEXT_NOTIFICATION_FLAG =
    115             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NOTIFICATION_FLAG;
    116     public static final int AUDIO_CONTEXT_UNKNOWN_FLAG =
    117             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_UNKNOWN_FLAG;
    118     public static final int AUDIO_CONTEXT_SAFETY_ALERT_FLAG =
    119             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SAFETY_ALERT_FLAG;
    120     public static final int AUDIO_CONTEXT_RADIO_FLAG =
    121             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG;
    122     public static final int AUDIO_CONTEXT_CD_ROM_FLAG =
    123             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CD_ROM_FLAG;
    124     public static final int AUDIO_CONTEXT_AUX_AUDIO_FLAG =
    125             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_AUX_AUDIO_FLAG;
    126     public static final int AUDIO_CONTEXT_SYSTEM_SOUND_FLAG =
    127             VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SYSTEM_SOUND_FLAG;
    128 
    129     public interface AudioHalListener {
    130         /**
    131          * Audio focus change from car.
    132          * @param focusState
    133          * @param streams
    134          * @param externalFocus Flags of active external audio focus.
    135          *            0 means no external audio focus.
    136          */
    137         void onFocusChange(int focusState, int streams, int externalFocus);
    138         /**
    139          * Audio volume change from car.
    140          * @param streamNumber
    141          * @param volume
    142          * @param volumeState
    143          */
    144         void onVolumeChange(int streamNumber, int volume, int volumeState);
    145         /**
    146          * Volume limit change from car.
    147          * @param streamNumber
    148          * @param volume
    149          */
    150         void onVolumeLimitChange(int streamNumber, int volume);
    151         /**
    152          * Stream state change (start / stop) from android
    153          * @param streamNumber
    154          * @param state
    155          */
    156         void onStreamStatusChange(int streamNumber, int state);
    157     }
    158 
    159     private final VehicleHal mVehicleHal;
    160     private AudioHalListener mListener;
    161     private int mVariant;
    162 
    163     private List<VehiclePropValue> mQueuedEvents;
    164 
    165     private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
    166 
    167     public AudioHalService(VehicleHal vehicleHal) {
    168         mVehicleHal = vehicleHal;
    169     }
    170 
    171     public void setListener(AudioHalListener listener) {
    172         List<VehiclePropValue> eventsToDispatch = null;
    173         synchronized (this) {
    174             mListener = listener;
    175             if (mQueuedEvents != null) {
    176                 eventsToDispatch = mQueuedEvents;
    177                 mQueuedEvents = null;
    178             }
    179         }
    180         if (eventsToDispatch != null) {
    181             dispatchEventToListener(listener, eventsToDispatch);
    182         }
    183     }
    184 
    185     public void setAudioRoutingPolicy(AudioRoutingPolicy policy) {
    186         VehicleNetwork vn = mVehicleHal.getVehicleNetwork();
    187         VehiclePropConfigs configs = vn.listProperties(
    188                 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY);
    189         if (configs == null) {
    190             Log.w(CarLog.TAG_AUDIO,
    191                     "Vehicle HAL did not implement VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY");
    192             return;
    193         }
    194         int[] policyToSet = new int[2];
    195         for (int i = 0; i < policy.getPhysicalStreamsCount(); i++) {
    196             policyToSet[VehicleAudioRoutingPolicyIndex.VEHICLE_AUDIO_ROUTING_POLICY_INDEX_STREAM] =
    197                     i;
    198             int contexts = 0;
    199             for (int logicalStream : policy.getLogicalStreamsForPhysicalStream(i)) {
    200                 contexts |= logicalStreamToHalContextType(logicalStream);
    201             }
    202             policyToSet[VehicleAudioRoutingPolicyIndex.VEHICLE_AUDIO_ROUTING_POLICY_INDEX_CONTEXTS]
    203                     = contexts;
    204             vn.setIntVectorProperty(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY,
    205                     policyToSet);
    206         }
    207     }
    208 
    209     /**
    210      * Convert car audio manager stream type (usage) into audio context type.
    211      */
    212     public static int logicalStreamToHalContextType(int logicalStream) {
    213         switch (logicalStream) {
    214             case CarAudioManager.CAR_AUDIO_USAGE_RADIO:
    215                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG;
    216             case CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL:
    217                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CALL_FLAG;
    218             case CarAudioManager.CAR_AUDIO_USAGE_MUSIC:
    219                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG;
    220             case CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE:
    221                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG;
    222             case CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND:
    223                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_VOICE_COMMAND_FLAG;
    224             case CarAudioManager.CAR_AUDIO_USAGE_ALARM:
    225                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_ALARM_FLAG;
    226             case CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION:
    227                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NOTIFICATION_FLAG;
    228             case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT:
    229                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SAFETY_ALERT_FLAG;
    230             case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND:
    231                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SYSTEM_SOUND_FLAG;
    232             case CarAudioManager.CAR_AUDIO_USAGE_DEFAULT:
    233                 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_UNKNOWN_FLAG;
    234             case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_BOTTOM:
    235             case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_CAR_PROXY:
    236                 // internal tag not associated with any stream
    237                 return 0;
    238             default:
    239                 Log.w(CarLog.TAG_AUDIO, "Unknown logical stream:" + logicalStream);
    240                 return 0;
    241         }
    242     }
    243 
    244     public void requestAudioFocusChange(int request, int streams, int audioContexts) {
    245         requestAudioFocusChange(request, streams, VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG, audioContexts);
    246     }
    247 
    248     public void requestAudioFocusChange(int request, int streams, int extFocus, int audioContexts) {
    249         int[] payload = { request, streams, extFocus, audioContexts };
    250         mVehicleHal.getVehicleNetwork().setIntVectorProperty(
    251                 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, payload);
    252     }
    253 
    254     public synchronized int getHwVariant() {
    255         return mVariant;
    256     }
    257 
    258     public synchronized boolean isRadioExternal() {
    259         VehiclePropConfig config = mProperties.get(
    260                 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT);
    261         if (config == null) {
    262             return true;
    263         }
    264         return (config.getConfigArray(0) &
    265                 VehicleAudioHwVariantConfigFlag.VEHICLE_AUDIO_HW_VARIANT_FLAG_PASS_RADIO_AUDIO_FOCUS_FLAG)
    266                 == 0;
    267     }
    268 
    269     public synchronized boolean isFocusSupported() {
    270         return isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS);
    271     }
    272 
    273     /**
    274      * Get the current audio focus state.
    275      * @return 0: focusState, 1: streams, 2: externalFocus
    276      */
    277     public int[] getCurrentFocusState() {
    278         if (!isFocusSupported()) {
    279             return new int[] { VEHICLE_AUDIO_FOCUS_STATE_GAIN, 0xffffffff, 0};
    280         }
    281         try {
    282             return mVehicleHal.getVehicleNetwork().getIntVectorProperty(
    283                     VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS);
    284         } catch (ServiceSpecificException e) {
    285             Log.e(CarLog.TAG_AUDIO, "VEHICLE_PROPERTY_AUDIO_HW_VARIANT not ready", e);
    286             return new int[] { VEHICLE_AUDIO_FOCUS_STATE_LOSS, 0x0, 0};
    287         }
    288     }
    289 
    290     private boolean isPropertySupportedLocked(int property) {
    291         VehiclePropConfig config = mProperties.get(property);
    292         return config != null;
    293     }
    294 
    295     @Override
    296     public synchronized void init() {
    297         for (VehiclePropConfig config : mProperties.values()) {
    298             if (VehicleHal.isPropertySubscribable(config)) {
    299                 mVehicleHal.subscribeProperty(this, config.getProp(), 0);
    300             }
    301         }
    302         try {
    303             mVariant = mVehicleHal.getVehicleNetwork().getIntProperty(
    304                     VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT);
    305         } catch (IllegalArgumentException e) {
    306             // no variant. Set to default, 0.
    307             mVariant = 0;
    308         } catch (ServiceSpecificException e) {
    309             Log.e(CarLog.TAG_AUDIO, "VEHICLE_PROPERTY_AUDIO_HW_VARIANT not ready", e);
    310             mVariant = 0;
    311         }
    312     }
    313 
    314     @Override
    315     public synchronized void release() {
    316         for (VehiclePropConfig config : mProperties.values()) {
    317             if (VehicleHal.isPropertySubscribable(config)) {
    318                 mVehicleHal.unsubscribeProperty(this, config.getProp());
    319             }
    320         }
    321         mProperties.clear();
    322     }
    323 
    324     @Override
    325     public synchronized List<VehiclePropConfig> takeSupportedProperties(
    326             List<VehiclePropConfig> allProperties) {
    327         for (VehiclePropConfig p : allProperties) {
    328             switch (p.getProp()) {
    329                 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS:
    330                 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME:
    331                 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT:
    332                 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT:
    333                 case VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE:
    334                     mProperties.put(p.getProp(), p);
    335                     break;
    336             }
    337         }
    338         return new LinkedList<VehiclePropConfig>(mProperties.values());
    339     }
    340 
    341     @Override
    342     public void handleHalEvents(List<VehiclePropValue> values) {
    343         AudioHalListener listener = null;
    344         synchronized (this) {
    345             listener = mListener;
    346             if (listener == null) {
    347                 if (mQueuedEvents == null) {
    348                     mQueuedEvents = new LinkedList<VehiclePropValue>();
    349                 }
    350                 mQueuedEvents.addAll(values);
    351             }
    352         }
    353         if (listener != null) {
    354             dispatchEventToListener(listener, values);
    355         }
    356     }
    357 
    358     private void dispatchEventToListener(AudioHalListener listener, List<VehiclePropValue> values) {
    359         for (VehiclePropValue v : values) {
    360             switch (v.getProp()) {
    361                 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS: {
    362                     int focusState = v.getInt32Values(
    363                             VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_FOCUS);
    364                     int streams = v.getInt32Values(
    365                             VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_STREAMS);
    366                     int externalFocus = v.getInt32Values(
    367                             VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_EXTERNAL_FOCUS_STATE);
    368                     listener.onFocusChange(focusState, streams, externalFocus);
    369                 } break;
    370                 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME: {
    371                     int volume = v.getInt32Values(
    372                             VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_VOLUME);
    373                     int streamNum = v.getInt32Values(
    374                             VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STREAM);
    375                     int volumeState = v.getInt32Values(
    376                             VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STATE);
    377                     listener.onVolumeChange(streamNum, volume, volumeState);
    378                 } break;
    379                 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT: {
    380                     //TODO
    381                 } break;
    382                 case VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: {
    383                     int state = v.getInt32Values(
    384                             VehicleAudioStreamStateIndex.VEHICLE_AUDIO_STREAM_STATE_INDEX_STATE);
    385                     int streamNum = v.getInt32Values(
    386                             VehicleAudioStreamStateIndex.VEHICLE_AUDIO_STREAM_STATE_INDEX_STREAM);
    387                     listener.onStreamStatusChange(streamNum, state);
    388                 } break;
    389             }
    390         }
    391     }
    392 
    393     @Override
    394     public void dump(PrintWriter writer) {
    395         writer.println("*Audio HAL*");
    396         writer.println(" audio H/W variant:" + mVariant);
    397         writer.println(" Supported properties");
    398         VehicleHal.dumpProperties(writer, mProperties.values());
    399     }
    400 
    401 }
    402