blob: 26f3237e074a2de5b9d86309c0943aacc43054f0 [file] [log] [blame]
keunyoungd32f4e62015-09-21 11:33:06 -07001/*
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
Pavel Maltsevcfe93102017-02-02 12:38:08 -080018import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_EXT_ROUTING_HINT;
19import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_FOCUS;
20import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_HW_VARIANT;
21import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_PARAMETERS;
22import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_ROUTING_POLICY;
23import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_VOLUME;
24import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_VOLUME_LIMIT;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070025import static com.android.car.CarServiceUtils.toIntArray;
26import static java.lang.Integer.toHexString;
27
28import android.annotation.Nullable;
Yao Chenc4d442f2016-04-08 11:33:47 -070029import android.car.VehicleZoneUtil;
Keun-young Parke54ac272016-02-16 19:02:18 -080030import android.car.media.CarAudioManager;
Keun-young Parkfe1a8f12017-01-17 20:06:34 -080031import android.car.media.CarAudioManager.OnParameterChangeListener;
Pavel Maltsevcfe93102017-02-02 12:38:08 -080032import android.hardware.automotive.vehicle.V2_0.VehicleAudioContextFlag;
33import android.hardware.automotive.vehicle.V2_0.VehicleAudioExtFocusFlag;
34import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusIndex;
35import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusRequest;
36import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusState;
37import android.hardware.automotive.vehicle.V2_0.VehicleAudioHwVariantConfigFlag;
38import android.hardware.automotive.vehicle.V2_0.VehicleAudioRoutingPolicyIndex;
39import android.hardware.automotive.vehicle.V2_0.VehicleAudioVolumeCapabilityFlag;
40import android.hardware.automotive.vehicle.V2_0.VehicleAudioVolumeIndex;
41import android.hardware.automotive.vehicle.V2_0.VehicleAudioVolumeLimitIndex;
42import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
43import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
44import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070045import android.text.TextUtils;
keunyoung5c7cb262015-10-19 10:47:45 -070046import android.util.Log;
47
48import com.android.car.AudioRoutingPolicy;
Keun-young Park9ba6e8b2016-03-04 16:21:19 -080049import com.android.car.CarAudioAttributesUtil;
keunyoung5c7cb262015-10-19 10:47:45 -070050import com.android.car.CarLog;
keunyoungd32f4e62015-09-21 11:33:06 -070051
52import java.io.PrintWriter;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070053import java.util.ArrayList;
54import java.util.Arrays;
55import java.util.Collection;
keunyounga74b9ca2015-10-21 13:33:58 -070056import java.util.HashMap;
keunyoungd32f4e62015-09-21 11:33:06 -070057import java.util.List;
Keun-young Park4c6834a2016-06-28 12:58:23 -070058import java.util.Map;
keunyoungd32f4e62015-09-21 11:33:06 -070059
60public class AudioHalService extends HalServiceBase {
keunyounga74b9ca2015-10-21 13:33:58 -070061 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_INVALID = -1;
keunyoungd32f4e62015-09-21 11:33:06 -070062 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070063 VehicleAudioFocusRequest.REQUEST_GAIN;
keunyoungd32f4e62015-09-21 11:33:06 -070064 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070065 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070066 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070067 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_MAY_DUCK;
Keun-young Park32b63822016-08-02 11:22:29 -070068 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_NO_DUCK =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070069 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_NO_DUCK;
keunyoungd32f4e62015-09-21 11:33:06 -070070 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070071 VehicleAudioFocusRequest.REQUEST_RELEASE;
keunyoungd32f4e62015-09-21 11:33:06 -070072
keunyounga74b9ca2015-10-21 13:33:58 -070073 public static final int VEHICLE_AUDIO_FOCUS_STATE_INVALID = -1;
keunyoungd32f4e62015-09-21 11:33:06 -070074 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070075 VehicleAudioFocusState.STATE_GAIN;
keunyoungd32f4e62015-09-21 11:33:06 -070076 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070077 VehicleAudioFocusState.STATE_GAIN_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070078 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070079 VehicleAudioFocusState.STATE_LOSS_TRANSIENT_CAN_DUCK;
keunyoungd32f4e62015-09-21 11:33:06 -070080 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070081 VehicleAudioFocusState.STATE_LOSS_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070082 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070083 VehicleAudioFocusState.STATE_LOSS;
keunyoungd32f4e62015-09-21 11:33:06 -070084 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070085 VehicleAudioFocusState.STATE_LOSS_TRANSIENT_EXLCUSIVE;
keunyoungd32f4e62015-09-21 11:33:06 -070086
Pavel Maltsev0d07c762016-11-03 16:40:15 -070087 // TODO(pavelm): we don't have internal properties anymore
88// public static final int VEHICLE_AUDIO_STREAM_STATE_STOPPED =
89// VehicleAudioStreamState.VEHICLE_AUDIO_STREAM_STATE_STOPPED;
90// public static final int VEHICLE_AUDIO_STREAM_STATE_STARTED =
91// VehicleAudioStreamState.VEHICLE_AUDIO_STREAM_STATE_STARTED;
keunyoungd32f4e62015-09-21 11:33:06 -070092
keunyounga74b9ca2015-10-21 13:33:58 -070093 public static final int VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070094 VehicleAudioExtFocusFlag.NONE_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -070095 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070096 VehicleAudioExtFocusFlag.PERMANENT_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -070097 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070098 VehicleAudioExtFocusFlag.TRANSIENT_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -070099 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700100 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG;
Keun-young Park3cb89102016-05-05 13:16:03 -0700101 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700102 VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -0700103
keunyoungd32f4e62015-09-21 11:33:06 -0700104 public static final int STREAM_NUM_DEFAULT = 0;
105
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800106 public static final int FOCUS_STATE_ARRAY_INDEX_STATE = 0;
107 public static final int FOCUS_STATE_ARRAY_INDEX_STREAMS = 1;
108 public static final int FOCUS_STATE_ARRAY_INDEX_EXTERNAL_FOCUS = 2;
109
Keun-young Park1488ef22016-02-25 14:00:54 -0800110 public static final int AUDIO_CONTEXT_MUSIC_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700111 VehicleAudioContextFlag.MUSIC_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800112 public static final int AUDIO_CONTEXT_NAVIGATION_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700113 VehicleAudioContextFlag.NAVIGATION_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800114 public static final int AUDIO_CONTEXT_VOICE_COMMAND_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700115 VehicleAudioContextFlag.VOICE_COMMAND_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800116 public static final int AUDIO_CONTEXT_CALL_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700117 VehicleAudioContextFlag.CALL_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800118 public static final int AUDIO_CONTEXT_ALARM_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700119 VehicleAudioContextFlag.ALARM_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800120 public static final int AUDIO_CONTEXT_NOTIFICATION_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700121 VehicleAudioContextFlag.NOTIFICATION_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800122 public static final int AUDIO_CONTEXT_UNKNOWN_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700123 VehicleAudioContextFlag.UNKNOWN_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800124 public static final int AUDIO_CONTEXT_SAFETY_ALERT_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700125 VehicleAudioContextFlag.SAFETY_ALERT_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800126 public static final int AUDIO_CONTEXT_RADIO_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700127 VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800128 public static final int AUDIO_CONTEXT_CD_ROM_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700129 VehicleAudioContextFlag.CD_ROM_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800130 public static final int AUDIO_CONTEXT_AUX_AUDIO_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700131 VehicleAudioContextFlag.AUX_AUDIO_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800132 public static final int AUDIO_CONTEXT_SYSTEM_SOUND_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700133 VehicleAudioContextFlag.SYSTEM_SOUND_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700134 public static final int AUDIO_CONTEXT_EXT_SOURCE_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700135 VehicleAudioContextFlag.EXT_SOURCE_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800136
Keun-young Park07182c72016-03-18 18:01:29 -0700137 public interface AudioHalFocusListener {
keunyounga74b9ca2015-10-21 13:33:58 -0700138 /**
139 * Audio focus change from car.
140 * @param focusState
141 * @param streams
142 * @param externalFocus Flags of active external audio focus.
143 * 0 means no external audio focus.
144 */
145 void onFocusChange(int focusState, int streams, int externalFocus);
146 /**
Keun-young Park07182c72016-03-18 18:01:29 -0700147 * Stream state change (start / stop) from android
Keun-young Park32b63822016-08-02 11:22:29 -0700148 * @param streamNumber stream number like 0, 1, ...
149 * @param streamActive Whether the stream is active or not.
Keun-young Park07182c72016-03-18 18:01:29 -0700150 */
Keun-young Park32b63822016-08-02 11:22:29 -0700151 void onStreamStatusChange(int streamNumber, boolean streamActive);
Keun-young Park07182c72016-03-18 18:01:29 -0700152 }
153
154 public interface AudioHalVolumeListener {
155 /**
keunyounga74b9ca2015-10-21 13:33:58 -0700156 * Audio volume change from car.
157 * @param streamNumber
158 * @param volume
159 * @param volumeState
160 */
keunyoung5c7cb262015-10-19 10:47:45 -0700161 void onVolumeChange(int streamNumber, int volume, int volumeState);
keunyounga74b9ca2015-10-21 13:33:58 -0700162 /**
163 * Volume limit change from car.
164 * @param streamNumber
165 * @param volume
166 */
167 void onVolumeLimitChange(int streamNumber, int volume);
keunyoungd32f4e62015-09-21 11:33:06 -0700168 }
169
Vitalii Tomkiv1b1247b2016-09-30 11:27:19 -0700170 private static final boolean DBG = false;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700171
keunyoungd32f4e62015-09-21 11:33:06 -0700172 private final VehicleHal mVehicleHal;
Keun-young Park07182c72016-03-18 18:01:29 -0700173 private AudioHalFocusListener mFocusListener;
174 private AudioHalVolumeListener mVolumeListener;
keunyoung5c7cb262015-10-19 10:47:45 -0700175 private int mVariant;
176
keunyounga74b9ca2015-10-21 13:33:58 -0700177 private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
178
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800179 private OnParameterChangeListener mOnParameterChangeListener;
180
keunyoungd32f4e62015-09-21 11:33:06 -0700181 public AudioHalService(VehicleHal vehicleHal) {
182 mVehicleHal = vehicleHal;
183 }
184
Keun-young Park6b3f7192016-03-25 18:41:49 -0700185 public synchronized void setFocusListener(AudioHalFocusListener focusListener) {
186 mFocusListener = focusListener;
Keun-young Park07182c72016-03-18 18:01:29 -0700187 }
188
Keun-young Park6b3f7192016-03-25 18:41:49 -0700189 public synchronized void setVolumeListener(AudioHalVolumeListener volumeListener) {
190 mVolumeListener = volumeListener;
keunyoung5c7cb262015-10-19 10:47:45 -0700191 }
192
193 public void setAudioRoutingPolicy(AudioRoutingPolicy policy) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700194 if (!mVehicleHal.isPropertySupported(VehicleProperty.AUDIO_ROUTING_POLICY)) {
keunyoung5c7cb262015-10-19 10:47:45 -0700195 Log.w(CarLog.TAG_AUDIO,
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700196 "Vehicle HAL did not implement VehicleProperty.AUDIO_ROUTING_POLICY");
keunyoung5c7cb262015-10-19 10:47:45 -0700197 return;
198 }
199 int[] policyToSet = new int[2];
200 for (int i = 0; i < policy.getPhysicalStreamsCount(); i++) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700201 policyToSet[VehicleAudioRoutingPolicyIndex.STREAM] = i;
Keun-young Park1488ef22016-02-25 14:00:54 -0800202 int contexts = 0;
keunyoung5c7cb262015-10-19 10:47:45 -0700203 for (int logicalStream : policy.getLogicalStreamsForPhysicalStream(i)) {
Keun-young Park1488ef22016-02-25 14:00:54 -0800204 contexts |= logicalStreamToHalContextType(logicalStream);
keunyoung5c7cb262015-10-19 10:47:45 -0700205 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700206 policyToSet[VehicleAudioRoutingPolicyIndex.CONTEXTS] = contexts;
Keun-young Parke78bf532016-04-25 18:59:22 -0700207 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700208 mVehicleHal.set(AUDIO_ROUTING_POLICY).to(policyToSet);
209 } catch (PropertyTimeoutException e) {
210 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_ROUTING_POLICY", e);
Keun-young Parke78bf532016-04-25 18:59:22 -0700211 }
keunyoung5c7cb262015-10-19 10:47:45 -0700212 }
213 }
214
Keun-young Park1488ef22016-02-25 14:00:54 -0800215 /**
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700216 * Returns the volume limits of a stream. Returns null if max value wasn't defined for
217 * AUDIO_VOLUME property.
Yao Chenc4d442f2016-04-08 11:33:47 -0700218 */
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700219 @Nullable
220 public synchronized Integer getStreamMaxVolume(int stream) {
221 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_VOLUME);
222 if (config == null) {
223 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Yao Chenc4d442f2016-04-08 11:33:47 -0700224 }
225 int supportedContext = getSupportedAudioVolumeContexts();
Yao Chenc4d442f2016-04-08 11:33:47 -0700226
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700227 int MAX_VALUES_FIRST_ELEMENT_INDEX = 4;
228 ArrayList<Integer> maxValues = new ArrayList<>();
229 for (int i = MAX_VALUES_FIRST_ELEMENT_INDEX; i < config.configArray.size(); i++) {
230 maxValues.add(config.configArray.get(i));
Yao Chenc4d442f2016-04-08 11:33:47 -0700231 }
232
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700233 Integer result = null;
Yao Chenc4d442f2016-04-08 11:33:47 -0700234 if (supportedContext != 0) {
235 int index = VehicleZoneUtil.zoneToIndex(supportedContext, stream);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700236 if (index < maxValues.size()) {
237 result = maxValues.get(index);
Yao Chenc4d442f2016-04-08 11:33:47 -0700238 }
239 } else {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700240 if (stream < maxValues.size()) {
241 result = maxValues.get(stream);
Yao Chenc4d442f2016-04-08 11:33:47 -0700242 }
243 }
244
245 if (result == null) {
246 Log.e(CarLog.TAG_AUDIO, "No min/max volume found in vehicle" +
247 " prop config for stream: " + stream);
248 }
249
250 return result;
251 }
252
253 /**
Keun-young Park1488ef22016-02-25 14:00:54 -0800254 * Convert car audio manager stream type (usage) into audio context type.
255 */
256 public static int logicalStreamToHalContextType(int logicalStream) {
Keun-young Park4c6834a2016-06-28 12:58:23 -0700257 return logicalStreamWithExtTypeToHalContextType(logicalStream, null);
258 }
259
260 public static int logicalStreamWithExtTypeToHalContextType(int logicalStream, String extType) {
keunyoung5c7cb262015-10-19 10:47:45 -0700261 switch (logicalStream) {
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800262 case CarAudioManager.CAR_AUDIO_USAGE_RADIO:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700263 return VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800264 case CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700265 return VehicleAudioContextFlag.CALL_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800266 case CarAudioManager.CAR_AUDIO_USAGE_MUSIC:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700267 return VehicleAudioContextFlag.MUSIC_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800268 case CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700269 return VehicleAudioContextFlag.NAVIGATION_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800270 case CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700271 return VehicleAudioContextFlag.VOICE_COMMAND_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800272 case CarAudioManager.CAR_AUDIO_USAGE_ALARM:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700273 return VehicleAudioContextFlag.ALARM_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800274 case CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700275 return VehicleAudioContextFlag.NOTIFICATION_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800276 case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700277 return VehicleAudioContextFlag.SAFETY_ALERT_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800278 case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700279 return VehicleAudioContextFlag.SYSTEM_SOUND_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800280 case CarAudioManager.CAR_AUDIO_USAGE_DEFAULT:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700281 return VehicleAudioContextFlag.UNKNOWN_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700282 case CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE:
283 if (extType != null) {
284 switch (extType) {
285 case CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_CD_DVD:
286 return AudioHalService.AUDIO_CONTEXT_CD_ROM_FLAG;
287 case CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_AUX_IN0:
288 case CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_AUX_IN1:
289 return AudioHalService.AUDIO_CONTEXT_AUX_AUDIO_FLAG;
290 default:
291 if (extType.startsWith("RADIO_")) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700292 return VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700293 } else {
294 return AudioHalService.AUDIO_CONTEXT_EXT_SOURCE_FLAG;
295 }
296 }
297 } else { // no external source specified. fall back to radio
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700298 return VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700299 }
Keun-young Park9ba6e8b2016-03-04 16:21:19 -0800300 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_BOTTOM:
301 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_CAR_PROXY:
Keun-young Park3cb89102016-05-05 13:16:03 -0700302 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_MEDIA_MUTE:
Keun-young Park9ba6e8b2016-03-04 16:21:19 -0800303 // internal tag not associated with any stream
304 return 0;
keunyoung5c7cb262015-10-19 10:47:45 -0700305 default:
306 Log.w(CarLog.TAG_AUDIO, "Unknown logical stream:" + logicalStream);
307 return 0;
308 }
keunyoungd32f4e62015-09-21 11:33:06 -0700309 }
310
Yao Chen75279c92016-05-06 14:41:37 -0700311 /**
312 * Converts car audio context type to car stream usage.
313 */
314 public static int carContextToCarUsage(int carContext) {
315 switch (carContext) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700316 case VehicleAudioContextFlag.MUSIC_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700317 return CarAudioManager.CAR_AUDIO_USAGE_MUSIC;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700318 case VehicleAudioContextFlag.NAVIGATION_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700319 return CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700320 case VehicleAudioContextFlag.ALARM_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700321 return CarAudioManager.CAR_AUDIO_USAGE_ALARM;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700322 case VehicleAudioContextFlag.VOICE_COMMAND_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700323 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700324 case VehicleAudioContextFlag.AUX_AUDIO_FLAG:
Keun-young Park4c6834a2016-06-28 12:58:23 -0700325 return CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700326 case VehicleAudioContextFlag.CALL_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700327 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700328 case VehicleAudioContextFlag.CD_ROM_FLAG:
Keun-young Park4c6834a2016-06-28 12:58:23 -0700329 return CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700330 case VehicleAudioContextFlag.NOTIFICATION_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700331 return CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700332 case VehicleAudioContextFlag.RADIO_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700333 return CarAudioManager.CAR_AUDIO_USAGE_RADIO;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700334 case VehicleAudioContextFlag.SAFETY_ALERT_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700335 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700336 case VehicleAudioContextFlag.SYSTEM_SOUND_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700337 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700338 case VehicleAudioContextFlag.UNKNOWN_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700339 return CarAudioManager.CAR_AUDIO_USAGE_DEFAULT;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700340 case VehicleAudioContextFlag.EXT_SOURCE_FLAG:
Keun-young Park4c6834a2016-06-28 12:58:23 -0700341 return CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
Yao Chen75279c92016-05-06 14:41:37 -0700342 default:
343 Log.w(CarLog.TAG_AUDIO, "Unknown car context:" + carContext);
344 return 0;
345 }
346 }
347
Keun-young Park1488ef22016-02-25 14:00:54 -0800348 public void requestAudioFocusChange(int request, int streams, int audioContexts) {
349 requestAudioFocusChange(request, streams, VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG, audioContexts);
keunyounga74b9ca2015-10-21 13:33:58 -0700350 }
351
Keun-young Park1488ef22016-02-25 14:00:54 -0800352 public void requestAudioFocusChange(int request, int streams, int extFocus, int audioContexts) {
353 int[] payload = { request, streams, extFocus, audioContexts };
Keun-young Parke78bf532016-04-25 18:59:22 -0700354 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700355 mVehicleHal.set(AUDIO_FOCUS).to(payload);
356 } catch (PropertyTimeoutException e) {
357 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_FOCUS", e);
Keun-young Parke78bf532016-04-25 18:59:22 -0700358 // focus timeout will reset it anyway
359 }
keunyoungd32f4e62015-09-21 11:33:06 -0700360 }
361
Yao Chenc4d442f2016-04-08 11:33:47 -0700362 public void setStreamVolume(int streamType, int index) {
363 int[] payload = {streamType, index, 0};
Keun-young Parke78bf532016-04-25 18:59:22 -0700364 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700365 mVehicleHal.set(VehicleProperty.AUDIO_VOLUME).to(payload);
366 } catch (PropertyTimeoutException e) {
367 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_VOLUME", e);
Keun-young Parkf9215202016-10-10 12:34:08 -0700368 //TODO should reset volume, bug: 32096870
Keun-young Parke78bf532016-04-25 18:59:22 -0700369 }
Yao Chenc4d442f2016-04-08 11:33:47 -0700370 }
371
372 public int getStreamVolume(int stream) {
373 int[] volume = {stream, 0, 0};
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700374 VehiclePropValue requestedStreamVolume = new VehiclePropValue();
375 requestedStreamVolume.prop = VehicleProperty.AUDIO_VOLUME;
376 requestedStreamVolume.value.int32Values.addAll(Arrays.asList(stream, 0 , 0));
377 VehiclePropValue propValue;
Keun-young Park021310d2016-04-25 21:09:39 -0700378 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700379 propValue = mVehicleHal.get(requestedStreamVolume);
380 } catch (PropertyTimeoutException e) {
381 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_VOLUME not ready", e);
Keun-young Park021310d2016-04-25 21:09:39 -0700382 return 0;
383 }
Yao Chenc4d442f2016-04-08 11:33:47 -0700384
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700385 if (propValue.value.int32Values.size() != 3) {
Yao Chenc4d442f2016-04-08 11:33:47 -0700386 Log.e(CarLog.TAG_AUDIO, "returned value not valid");
387 throw new IllegalStateException("Invalid preset returned from service: "
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700388 + Arrays.toString(propValue.value.int32Values.toArray()));
Yao Chenc4d442f2016-04-08 11:33:47 -0700389 }
390
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700391 int retStreamNum = propValue.value.int32Values.get(0);
392 int retVolume = propValue.value.int32Values.get(1);
393 int retVolumeState = propValue.value.int32Values.get(2);
Yao Chenc4d442f2016-04-08 11:33:47 -0700394
395 if (retStreamNum != stream) {
396 Log.e(CarLog.TAG_AUDIO, "Stream number is not the same: "
397 + stream + " vs " + retStreamNum);
398 throw new IllegalStateException("Stream number is not the same");
399 }
400 return retVolume;
401 }
402
keunyoung5c7cb262015-10-19 10:47:45 -0700403 public synchronized int getHwVariant() {
404 return mVariant;
405 }
406
keunyounga74b9ca2015-10-21 13:33:58 -0700407 public synchronized boolean isRadioExternal() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700408 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_HW_VARIANT);
keunyounga74b9ca2015-10-21 13:33:58 -0700409 if (config == null) {
410 return true;
411 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700412 return (config.configArray.get(0)
413 & VehicleAudioHwVariantConfigFlag.INTERNAL_RADIO_FLAG) == 0;
keunyounga74b9ca2015-10-21 13:33:58 -0700414 }
415
416 public synchronized boolean isFocusSupported() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700417 return isPropertySupportedLocked(AUDIO_FOCUS);
keunyounga74b9ca2015-10-21 13:33:58 -0700418 }
419
Keun-young Park07182c72016-03-18 18:01:29 -0700420 public synchronized boolean isAudioVolumeSupported() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700421 return isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME);
Keun-young Park07182c72016-03-18 18:01:29 -0700422 }
423
424 public synchronized int getSupportedAudioVolumeContexts() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700425 if (!isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME)) {
426 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Keun-young Park07182c72016-03-18 18:01:29 -0700427 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700428 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_VOLUME);
429 return config.configArray.get(0);
Keun-young Park07182c72016-03-18 18:01:29 -0700430 }
431
432 /**
433 * Whether external audio module can memorize logical audio volumes or not.
434 * @return
435 */
436 public synchronized boolean isExternalAudioVolumePersistent() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700437 if (!isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME)) {
438 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Keun-young Park07182c72016-03-18 18:01:29 -0700439 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700440 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_VOLUME);
441 if (config.configArray.get(0) == 0) { // physical streams only
Keun-young Park07182c72016-03-18 18:01:29 -0700442 return false;
443 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700444 if ((config.configArray.get(1)
445 & VehicleAudioVolumeCapabilityFlag.PERSISTENT_STORAGE) != 0) {
Keun-young Park07182c72016-03-18 18:01:29 -0700446 return true;
447 }
448 return false;
449 }
450
451 public synchronized boolean isAudioVolumeLimitSupported() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700452 return isPropertySupportedLocked(AUDIO_VOLUME_LIMIT);
Keun-young Park07182c72016-03-18 18:01:29 -0700453 }
454
Keun-young Parkd36a9952016-05-24 10:03:59 -0700455 public synchronized boolean isAudioVolumeMasterOnly() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700456 if (!isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME)) {
457 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Keun-young Parkd36a9952016-05-24 10:03:59 -0700458 }
459 VehiclePropConfig config = mProperties.get(
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700460 AUDIO_VOLUME);
461 if ((config.configArray.get(1) &
462 VehicleAudioVolumeCapabilityFlag.MASTER_VOLUME_ONLY)
Keun-young Parkd36a9952016-05-24 10:03:59 -0700463 != 0) {
464 return true;
465 }
466 return false;
467 }
468
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800469 /**
470 * Get the current audio focus state.
471 * @return 0: focusState, 1: streams, 2: externalFocus
472 */
473 public int[] getCurrentFocusState() {
474 if (!isFocusSupported()) {
475 return new int[] { VEHICLE_AUDIO_FOCUS_STATE_GAIN, 0xffffffff, 0};
476 }
Keun-young Parkba485482016-03-24 13:24:31 -0700477 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700478 VehiclePropValue propValue = mVehicleHal.get(VehicleProperty.AUDIO_FOCUS);
479 return toIntArray(propValue.value.int32Values);
480 } catch (PropertyTimeoutException e) {
481 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_HW_VARIANT not ready", e);
Keun-young Parkba485482016-03-24 13:24:31 -0700482 return new int[] { VEHICLE_AUDIO_FOCUS_STATE_LOSS, 0x0, 0};
483 }
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800484 }
485
Keun-young Park4c6834a2016-06-28 12:58:23 -0700486 public static class ExtRoutingSourceInfo {
487 /** Represents an external route which will not disable any physical stream in android side.
488 */
489 public static final int NO_DISABLED_PHYSICAL_STREAM = -1;
490
491 /** Bit position of this source in vhal */
492 public final int bitPosition;
493 /**
494 * Physical stream replaced by this routing. will be {@link #NO_DISABLED_PHYSICAL_STREAM}
495 * if no physical stream for android is replaced by this routing.
496 */
497 public final int physicalStreamNumber;
498
499 public ExtRoutingSourceInfo(int bitPosition, int physycalStreamNumber) {
500 this.bitPosition = bitPosition;
501 this.physicalStreamNumber = physycalStreamNumber;
502 }
503
504 @Override
505 public String toString() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700506 return "[bitPosition=" + bitPosition + ", physicalStreamNumber="
Keun-young Park4c6834a2016-06-28 12:58:23 -0700507 + physicalStreamNumber + "]";
508 }
509 }
510
511 /**
512 * Get external audio routing types from AUDIO_EXT_ROUTING_HINT property.
513 *
514 * @return null if AUDIO_EXT_ROUTING_HINT is not supported.
515 */
516 public Map<String, ExtRoutingSourceInfo> getExternalAudioRoutingTypes() {
517 VehiclePropConfig config;
518 synchronized (this) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700519 if (!isPropertySupportedLocked(AUDIO_EXT_ROUTING_HINT)) {
520 if (DBG) {
521 Log.i(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT is not supported");
522 }
Keun-young Park4c6834a2016-06-28 12:58:23 -0700523 return null;
524 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700525 config = mProperties.get(AUDIO_EXT_ROUTING_HINT);
Keun-young Park4c6834a2016-06-28 12:58:23 -0700526 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700527 if (TextUtils.isEmpty(config.configString)) {
528 Log.w(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT with empty config string");
Keun-young Park4c6834a2016-06-28 12:58:23 -0700529 return null;
530 }
531 Map<String, ExtRoutingSourceInfo> routingTypes = new HashMap<>();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700532 String configString = config.configString;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700533 if (DBG) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700534 Log.i(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT config string:" + configString);
Keun-young Park4c6834a2016-06-28 12:58:23 -0700535 }
536 String[] routes = configString.split(",");
537 for (String routeString : routes) {
538 String[] tokens = routeString.split(":");
539 int bitPosition = 0;
540 String name = null;
541 int physicalStreamNumber = ExtRoutingSourceInfo.NO_DISABLED_PHYSICAL_STREAM;
542 if (tokens.length == 2) {
543 bitPosition = Integer.parseInt(tokens[0]);
544 name = tokens[1];
545 } else if (tokens.length == 3) {
546 bitPosition = Integer.parseInt(tokens[0]);
547 name = tokens[1];
548 physicalStreamNumber = Integer.parseInt(tokens[2]);
549 } else {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700550 Log.w(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT has wrong entry:" +
Keun-young Park4c6834a2016-06-28 12:58:23 -0700551 routeString);
552 continue;
553 }
554 routingTypes.put(name, new ExtRoutingSourceInfo(bitPosition, physicalStreamNumber));
555 }
556 return routingTypes;
557 }
558
559 public void setExternalRoutingSource(int[] externalRoutings) {
560 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700561 mVehicleHal.set(AUDIO_EXT_ROUTING_HINT).to(externalRoutings);
562 } catch (PropertyTimeoutException e) {
563 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_EXT_ROUTING_HINT", e);
Keun-young Park4c6834a2016-06-28 12:58:23 -0700564 }
565 }
566
keunyounga74b9ca2015-10-21 13:33:58 -0700567 private boolean isPropertySupportedLocked(int property) {
568 VehiclePropConfig config = mProperties.get(property);
569 return config != null;
570 }
571
keunyoungd32f4e62015-09-21 11:33:06 -0700572 @Override
573 public synchronized void init() {
keunyounga74b9ca2015-10-21 13:33:58 -0700574 for (VehiclePropConfig config : mProperties.values()) {
575 if (VehicleHal.isPropertySubscribable(config)) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700576 mVehicleHal.subscribeProperty(this, config.prop, 0);
keunyoung5c7cb262015-10-19 10:47:45 -0700577 }
578 }
579 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700580 mVariant = mVehicleHal.get(int.class, AUDIO_HW_VARIANT);
keunyoung5c7cb262015-10-19 10:47:45 -0700581 } catch (IllegalArgumentException e) {
582 // no variant. Set to default, 0.
583 mVariant = 0;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700584 } catch (PropertyTimeoutException e) {
585 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_HW_VARIANT not ready", e);
Keun-young Parkba485482016-03-24 13:24:31 -0700586 mVariant = 0;
keunyoungd32f4e62015-09-21 11:33:06 -0700587 }
588 }
589
590 @Override
591 public synchronized void release() {
keunyounga74b9ca2015-10-21 13:33:58 -0700592 for (VehiclePropConfig config : mProperties.values()) {
593 if (VehicleHal.isPropertySubscribable(config)) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700594 mVehicleHal.unsubscribeProperty(this, config.prop);
keunyoung5c7cb262015-10-19 10:47:45 -0700595 }
keunyoungd32f4e62015-09-21 11:33:06 -0700596 }
keunyounga74b9ca2015-10-21 13:33:58 -0700597 mProperties.clear();
keunyoungd32f4e62015-09-21 11:33:06 -0700598 }
599
600 @Override
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700601 public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
602 Collection<VehiclePropConfig> allProperties) {
keunyoungd32f4e62015-09-21 11:33:06 -0700603 for (VehiclePropConfig p : allProperties) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700604 switch (p.prop) {
605 case VehicleProperty.AUDIO_FOCUS:
606 case VehicleProperty.AUDIO_VOLUME:
607 case VehicleProperty.AUDIO_VOLUME_LIMIT:
608 case VehicleProperty.AUDIO_HW_VARIANT:
609 case VehicleProperty.AUDIO_EXT_ROUTING_HINT:
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800610 case VehicleProperty.AUDIO_PARAMETERS:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700611 // TODO(pavelm): we don't have internal properties anymore.
612// case VehicleProperty.INTERNAL_AUDIO_STREAM_STATE:
613 mProperties.put(p.prop, p);
keunyoungd32f4e62015-09-21 11:33:06 -0700614 break;
615 }
616 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700617 return new ArrayList<>(mProperties.values());
keunyoungd32f4e62015-09-21 11:33:06 -0700618 }
619
620 @Override
621 public void handleHalEvents(List<VehiclePropValue> values) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700622 AudioHalFocusListener focusListener;
623 AudioHalVolumeListener volumeListener;
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800624 OnParameterChangeListener parameterListener;
keunyoungd32f4e62015-09-21 11:33:06 -0700625 synchronized (this) {
Keun-young Park07182c72016-03-18 18:01:29 -0700626 focusListener = mFocusListener;
627 volumeListener = mVolumeListener;
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800628 parameterListener = mOnParameterChangeListener;
keunyoungd32f4e62015-09-21 11:33:06 -0700629 }
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800630 dispatchEventToListener(focusListener, volumeListener, parameterListener, values);
631 }
632
633 public String[] getAudioParameterKeys() {
634 VehiclePropConfig config;
635 synchronized (this) {
636 if (!isPropertySupportedLocked(AUDIO_PARAMETERS)) {
637 if (DBG) {
638 Log.i(CarLog.TAG_AUDIO, "AUDIO_PARAMETERS is not supported");
639 }
640 return null;
641 }
642 config = mProperties.get(AUDIO_PARAMETERS);
643 }
644 return config.configString.split(";");
645 }
646
647 public void setAudioParameters(String parameters) {
648 synchronized (this) {
649 if (!isPropertySupportedLocked(AUDIO_PARAMETERS)) {
650 throw new IllegalStateException("VehicleProperty.AUDIO_PARAMETERS not supported");
651 }
652 }
653 VehiclePropValue value = new VehiclePropValue();
654 value.prop = AUDIO_PARAMETERS;
655 value.value.stringValue = parameters;
656 try {
657 mVehicleHal.set(value);
658 } catch (PropertyTimeoutException e) {
659 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_EXT_ROUTING_HINT", e);
660 }
661 }
662
663 public String getAudioParameters(String keys) {
664 synchronized (this) {
665 if (!isPropertySupportedLocked(AUDIO_PARAMETERS)) {
666 throw new IllegalStateException("VehicleProperty.AUDIO_PARAMETERS not supported");
667 }
668 }
669 try {
670 VehiclePropValue requested = new VehiclePropValue();
671 requested.prop = AUDIO_PARAMETERS;
672 requested.value.stringValue = keys;
673 VehiclePropValue propValue = mVehicleHal.get(requested);
674 return propValue.value.stringValue;
675 } catch (PropertyTimeoutException e) {
676 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_PARAMETERS not ready", e);
677 return new String("");
678 }
679 }
680
681 public synchronized void setOnParameterChangeListener(OnParameterChangeListener listener) {
682 mOnParameterChangeListener = listener;
Keun-young Park07182c72016-03-18 18:01:29 -0700683 }
684
685 private void dispatchEventToListener(AudioHalFocusListener focusListener,
686 AudioHalVolumeListener volumeListener,
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800687 OnParameterChangeListener parameterListener,
Keun-young Park07182c72016-03-18 18:01:29 -0700688 List<VehiclePropValue> values) {
keunyoungd32f4e62015-09-21 11:33:06 -0700689 for (VehiclePropValue v : values) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700690 switch (v.prop) {
691 case VehicleProperty.AUDIO_FOCUS: {
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800692 ArrayList<Integer> vec = v.value.int32Values;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700693 int focusState = vec.get(VehicleAudioFocusIndex.FOCUS);
694 int streams = vec.get(VehicleAudioFocusIndex.STREAMS);
695 int externalFocus = vec.get(VehicleAudioFocusIndex.EXTERNAL_FOCUS_STATE);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700696 if (focusListener != null) {
697 focusListener.onFocusChange(focusState, streams, externalFocus);
698 }
699 } break;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700700 // TODO(pavelm): we don't have internal properties anymore
701// case INTERNAL_AUDIO_STREAM_STATE: {
702// int state = v.getInt32Values(
703// VehicleAudioStreamStateIndex.VEHICLE_AUDIO_STREAM_STATE_INDEX_STATE);
704// int streamNum = v.getInt32Values(
705// VehicleAudioStreamStateIndex.VEHICLE_AUDIO_STREAM_STATE_INDEX_STREAM);
706// if (focusListener != null) {
707// focusListener.onStreamStatusChange(streamNum, state ==
708// VehicleAudioStreamState.VEHICLE_AUDIO_STREAM_STATE_STARTED);
709// }
710// } break;
711 case AUDIO_VOLUME: {
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800712 ArrayList<Integer> vec = v.value.int32Values;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700713 int volume = vec.get(VehicleAudioVolumeIndex.INDEX_VOLUME);
714 int streamNum = vec.get(VehicleAudioVolumeIndex.INDEX_STREAM);
715 int volumeState = vec.get(VehicleAudioVolumeIndex.INDEX_STATE);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700716 if (volumeListener != null) {
717 volumeListener.onVolumeChange(streamNum, volume, volumeState);
718 }
keunyoung5c7cb262015-10-19 10:47:45 -0700719 } break;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700720 case AUDIO_VOLUME_LIMIT: {
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800721 ArrayList<Integer> vec = v.value.int32Values;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700722 int stream = vec.get(VehicleAudioVolumeLimitIndex.STREAM);
723 int maxVolume = vec.get(VehicleAudioVolumeLimitIndex.MAX_VOLUME);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700724 if (volumeListener != null) {
725 volumeListener.onVolumeLimitChange(stream, maxVolume);
726 }
keunyoungd32f4e62015-09-21 11:33:06 -0700727 } break;
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800728 case AUDIO_PARAMETERS: {
729 String params = v.value.stringValue;
730 if (parameterListener != null) {
731 parameterListener.onParameterChange(params);
732 }
733 }
keunyoungd32f4e62015-09-21 11:33:06 -0700734 }
735 }
Keun-young Park07182c72016-03-18 18:01:29 -0700736 values.clear();
keunyoungd32f4e62015-09-21 11:33:06 -0700737 }
738
739 @Override
740 public void dump(PrintWriter writer) {
keunyoung5c7cb262015-10-19 10:47:45 -0700741 writer.println("*Audio HAL*");
742 writer.println(" audio H/W variant:" + mVariant);
keunyounga74b9ca2015-10-21 13:33:58 -0700743 writer.println(" Supported properties");
744 VehicleHal.dumpProperties(writer, mProperties.values());
keunyoungd32f4e62015-09-21 11:33:06 -0700745 }
746
747}