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 */ 16package com.android.car.hal; 17 18import android.car.media.CarAudioManager; 19import android.os.ServiceSpecificException; 20import android.util.Log; 21 22import com.android.car.AudioRoutingPolicy; 23import com.android.car.CarAudioAttributesUtil; 24import com.android.car.CarLog; 25import com.android.car.vehiclenetwork.VehicleNetwork; 26import com.android.car.vehiclenetwork.VehicleNetworkConsts; 27import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioContextFlag; 28import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioExtFocusFlag; 29import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusIndex; 30import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequest; 31import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState; 32import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioHwVariantConfigFlag; 33import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioRoutingPolicyIndex; 34import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamState; 35import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamStateIndex; 36import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioVolumeIndex; 37import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig; 38import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs; 39import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue; 40 41import java.io.PrintWriter; 42import java.util.HashMap; 43import java.util.LinkedList; 44import java.util.List; 45 46public 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