blob: 8d650c9f337df0e8dc76d059194e959058e73b67 [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
Yao Chenc4d442f2016-04-08 11:33:47 -070018import android.car.VehicleZoneUtil;
Keun-young Parke54ac272016-02-16 19:02:18 -080019import android.car.media.CarAudioManager;
Keun-young Parkba485482016-03-24 13:24:31 -070020import android.os.ServiceSpecificException;
keunyoung5c7cb262015-10-19 10:47:45 -070021import android.util.Log;
Yao Chenc4d442f2016-04-08 11:33:47 -070022import android.util.Pair;
keunyoung5c7cb262015-10-19 10:47:45 -070023
24import com.android.car.AudioRoutingPolicy;
Keun-young Park9ba6e8b2016-03-04 16:21:19 -080025import com.android.car.CarAudioAttributesUtil;
keunyoung5c7cb262015-10-19 10:47:45 -070026import com.android.car.CarLog;
27import com.android.car.vehiclenetwork.VehicleNetwork;
keunyoungd32f4e62015-09-21 11:33:06 -070028import com.android.car.vehiclenetwork.VehicleNetworkConsts;
Keun-young Park0727f952015-12-21 14:30:07 -080029import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioContextFlag;
keunyounga74b9ca2015-10-21 13:33:58 -070030import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioExtFocusFlag;
31import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusIndex;
keunyoung1ab8e182015-09-24 09:25:22 -070032import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusRequest;
33import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioFocusState;
keunyounga74b9ca2015-10-21 13:33:58 -070034import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioHwVariantConfigFlag;
keunyoung5c7cb262015-10-19 10:47:45 -070035import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioRoutingPolicyIndex;
keunyoungd32f4e62015-09-21 11:33:06 -070036import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamState;
keunyounga74b9ca2015-10-21 13:33:58 -070037import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioStreamStateIndex;
Keun-young Park07182c72016-03-18 18:01:29 -070038import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioVolumeCapabilityFlag;
keunyounga74b9ca2015-10-21 13:33:58 -070039import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioVolumeIndex;
Keun-young Park07182c72016-03-18 18:01:29 -070040import com.android.car.vehiclenetwork.VehicleNetworkConsts.VehicleAudioVolumeLimitIndex;
keunyoungd32f4e62015-09-21 11:33:06 -070041import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfig;
keunyoung5c7cb262015-10-19 10:47:45 -070042import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropConfigs;
keunyoungd32f4e62015-09-21 11:33:06 -070043import com.android.car.vehiclenetwork.VehicleNetworkProto.VehiclePropValue;
Yao Chenc4d442f2016-04-08 11:33:47 -070044import com.android.car.vehiclenetwork.VehiclePropValueUtil;
keunyoungd32f4e62015-09-21 11:33:06 -070045
46import java.io.PrintWriter;
keunyounga74b9ca2015-10-21 13:33:58 -070047import java.util.HashMap;
keunyoungd32f4e62015-09-21 11:33:06 -070048import java.util.LinkedList;
49import java.util.List;
50
51public class AudioHalService extends HalServiceBase {
keunyounga74b9ca2015-10-21 13:33:58 -070052 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_INVALID = -1;
keunyoungd32f4e62015-09-21 11:33:06 -070053 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN =
keunyoung1ab8e182015-09-24 09:25:22 -070054 VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN;
keunyoungd32f4e62015-09-21 11:33:06 -070055 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT =
keunyoung1ab8e182015-09-24 09:25:22 -070056 VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070057 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK =
keunyoung1ab8e182015-09-24 09:25:22 -070058 VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK;
keunyoungd32f4e62015-09-21 11:33:06 -070059 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE =
keunyoung1ab8e182015-09-24 09:25:22 -070060 VehicleAudioFocusRequest.VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE;
keunyoungd32f4e62015-09-21 11:33:06 -070061
62 public static String audioFocusRequestToString(int request) {
keunyoung1ab8e182015-09-24 09:25:22 -070063 return VehicleAudioFocusRequest.enumToString(request);
keunyoungd32f4e62015-09-21 11:33:06 -070064 }
65
keunyounga74b9ca2015-10-21 13:33:58 -070066 public static final int VEHICLE_AUDIO_FOCUS_STATE_INVALID = -1;
keunyoungd32f4e62015-09-21 11:33:06 -070067 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN =
keunyoung1ab8e182015-09-24 09:25:22 -070068 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN;
keunyoungd32f4e62015-09-21 11:33:06 -070069 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT =
keunyoung1ab8e182015-09-24 09:25:22 -070070 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070071 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK =
keunyoung1ab8e182015-09-24 09:25:22 -070072 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK;
keunyoungd32f4e62015-09-21 11:33:06 -070073 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT =
keunyoung1ab8e182015-09-24 09:25:22 -070074 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070075 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS =
keunyoung1ab8e182015-09-24 09:25:22 -070076 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS;
keunyoungd32f4e62015-09-21 11:33:06 -070077 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE =
keunyoung1ab8e182015-09-24 09:25:22 -070078 VehicleAudioFocusState.VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE;
keunyoungd32f4e62015-09-21 11:33:06 -070079
80 public static String audioFocusStateToString(int state) {
keunyoung1ab8e182015-09-24 09:25:22 -070081 return VehicleAudioFocusState.enumToString(state);
keunyoungd32f4e62015-09-21 11:33:06 -070082 }
83
84 public static final int VEHICLE_AUDIO_STREAM_STATE_STOPPED =
85 VehicleAudioStreamState.VEHICLE_AUDIO_STREAM_STATE_STOPPED;
86 public static final int VEHICLE_AUDIO_STREAM_STATE_STARTED =
87 VehicleAudioStreamState.VEHICLE_AUDIO_STREAM_STATE_STARTED;
88
89 public static String audioStreamStateToString(int state) {
90 return VehicleAudioStreamState.enumToString(state);
91 }
92
keunyounga74b9ca2015-10-21 13:33:58 -070093 public static final int VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG =
94 VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG;
95 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG =
96 VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG;
97 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT_FLAG =
98 VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT_FLAG;
99 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG =
100 VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG;
Keun-young Park3cb89102016-05-05 13:16:03 -0700101 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG =
102 VehicleAudioExtFocusFlag.VEHICLE_AUDIO_EXT_FOCUS_CAR_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 =
111 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG;
112 public static final int AUDIO_CONTEXT_NAVIGATION_FLAG =
113 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG;
114 public static final int AUDIO_CONTEXT_VOICE_COMMAND_FLAG =
115 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_VOICE_COMMAND_FLAG;
116 public static final int AUDIO_CONTEXT_CALL_FLAG =
117 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CALL_FLAG;
118 public static final int AUDIO_CONTEXT_ALARM_FLAG =
119 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_ALARM_FLAG;
120 public static final int AUDIO_CONTEXT_NOTIFICATION_FLAG =
121 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NOTIFICATION_FLAG;
122 public static final int AUDIO_CONTEXT_UNKNOWN_FLAG =
123 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_UNKNOWN_FLAG;
124 public static final int AUDIO_CONTEXT_SAFETY_ALERT_FLAG =
125 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SAFETY_ALERT_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800126 public static final int AUDIO_CONTEXT_RADIO_FLAG =
127 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG;
128 public static final int AUDIO_CONTEXT_CD_ROM_FLAG =
129 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CD_ROM_FLAG;
130 public static final int AUDIO_CONTEXT_AUX_AUDIO_FLAG =
131 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_AUX_AUDIO_FLAG;
132 public static final int AUDIO_CONTEXT_SYSTEM_SOUND_FLAG =
133 VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SYSTEM_SOUND_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800134
Keun-young Park07182c72016-03-18 18:01:29 -0700135 public interface AudioHalFocusListener {
keunyounga74b9ca2015-10-21 13:33:58 -0700136 /**
137 * Audio focus change from car.
138 * @param focusState
139 * @param streams
140 * @param externalFocus Flags of active external audio focus.
141 * 0 means no external audio focus.
142 */
143 void onFocusChange(int focusState, int streams, int externalFocus);
144 /**
Keun-young Park07182c72016-03-18 18:01:29 -0700145 * Stream state change (start / stop) from android
146 * @param streamNumber
147 * @param state
148 */
149 void onStreamStatusChange(int streamNumber, int state);
150 }
151
152 public interface AudioHalVolumeListener {
153 /**
keunyounga74b9ca2015-10-21 13:33:58 -0700154 * Audio volume change from car.
155 * @param streamNumber
156 * @param volume
157 * @param volumeState
158 */
keunyoung5c7cb262015-10-19 10:47:45 -0700159 void onVolumeChange(int streamNumber, int volume, int volumeState);
keunyounga74b9ca2015-10-21 13:33:58 -0700160 /**
161 * Volume limit change from car.
162 * @param streamNumber
163 * @param volume
164 */
165 void onVolumeLimitChange(int streamNumber, int volume);
keunyoungd32f4e62015-09-21 11:33:06 -0700166 }
167
168 private final VehicleHal mVehicleHal;
Keun-young Park07182c72016-03-18 18:01:29 -0700169 private AudioHalFocusListener mFocusListener;
170 private AudioHalVolumeListener mVolumeListener;
keunyoung5c7cb262015-10-19 10:47:45 -0700171 private int mVariant;
172
keunyounga74b9ca2015-10-21 13:33:58 -0700173 private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
174
keunyoungd32f4e62015-09-21 11:33:06 -0700175 public AudioHalService(VehicleHal vehicleHal) {
176 mVehicleHal = vehicleHal;
177 }
178
Keun-young Park6b3f7192016-03-25 18:41:49 -0700179 public synchronized void setFocusListener(AudioHalFocusListener focusListener) {
180 mFocusListener = focusListener;
Keun-young Park07182c72016-03-18 18:01:29 -0700181 }
182
Keun-young Park6b3f7192016-03-25 18:41:49 -0700183 public synchronized void setVolumeListener(AudioHalVolumeListener volumeListener) {
184 mVolumeListener = volumeListener;
keunyoung5c7cb262015-10-19 10:47:45 -0700185 }
186
187 public void setAudioRoutingPolicy(AudioRoutingPolicy policy) {
188 VehicleNetwork vn = mVehicleHal.getVehicleNetwork();
189 VehiclePropConfigs configs = vn.listProperties(
190 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY);
191 if (configs == null) {
192 Log.w(CarLog.TAG_AUDIO,
193 "Vehicle HAL did not implement VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY");
194 return;
195 }
196 int[] policyToSet = new int[2];
197 for (int i = 0; i < policy.getPhysicalStreamsCount(); i++) {
198 policyToSet[VehicleAudioRoutingPolicyIndex.VEHICLE_AUDIO_ROUTING_POLICY_INDEX_STREAM] =
199 i;
Keun-young Park1488ef22016-02-25 14:00:54 -0800200 int contexts = 0;
keunyoung5c7cb262015-10-19 10:47:45 -0700201 for (int logicalStream : policy.getLogicalStreamsForPhysicalStream(i)) {
Keun-young Park1488ef22016-02-25 14:00:54 -0800202 contexts |= logicalStreamToHalContextType(logicalStream);
keunyoung5c7cb262015-10-19 10:47:45 -0700203 }
204 policyToSet[VehicleAudioRoutingPolicyIndex.VEHICLE_AUDIO_ROUTING_POLICY_INDEX_CONTEXTS]
Keun-young Park1488ef22016-02-25 14:00:54 -0800205 = contexts;
Keun-young Parke78bf532016-04-25 18:59:22 -0700206 try {
207 vn.setIntVectorProperty(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY,
208 policyToSet);
209 } catch (ServiceSpecificException e) {
210 Log.e(CarLog.TAG_AUDIO, "Cannot write to VEHICLE_PROPERTY_AUDIO_ROUTING_POLICY", e);
211 }
keunyoung5c7cb262015-10-19 10:47:45 -0700212 }
213 }
214
Keun-young Park1488ef22016-02-25 14:00:54 -0800215 /**
Yao Chenc4d442f2016-04-08 11:33:47 -0700216 * Returns the volume limits of a stream in the form <min, max>.
217 */
218 public Pair<Integer, Integer> getStreamVolumeLimit(int stream) {
219 if (!isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME)) {
220 throw new IllegalStateException("VEHICLE_PROPERTY_AUDIO_VOLUME not supported");
221 }
222 int supportedContext = getSupportedAudioVolumeContexts();
223 VehiclePropConfig config = mProperties.get(
224 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
225 List<Integer> maxs = config.getInt32MaxsList();
226 List<Integer> mins = config.getInt32MinsList();
227
228 if (maxs.size() != mins.size()) {
229 Log.e(CarLog.TAG_AUDIO, "Invalid volume prop config");
230 return null;
231 }
232
233 Pair<Integer, Integer> result = null;
234 if (supportedContext != 0) {
235 int index = VehicleZoneUtil.zoneToIndex(supportedContext, stream);
236 if (index < maxs.size()) {
237 result = new Pair<>(mins.get(index), maxs.get(index));
238 }
239 } else {
240 if (stream < maxs.size()) {
241 result = new Pair<>(mins.get(stream), maxs.get(stream));
242 }
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) {
keunyoung5c7cb262015-10-19 10:47:45 -0700257 switch (logicalStream) {
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800258 case CarAudioManager.CAR_AUDIO_USAGE_RADIO:
259 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800260 case CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL:
Keun-young Park0727f952015-12-21 14:30:07 -0800261 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CALL_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800262 case CarAudioManager.CAR_AUDIO_USAGE_MUSIC:
Keun-young Park0727f952015-12-21 14:30:07 -0800263 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800264 case CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE:
Keun-young Park0727f952015-12-21 14:30:07 -0800265 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800266 case CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND:
Keun-young Park0727f952015-12-21 14:30:07 -0800267 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_VOICE_COMMAND_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800268 case CarAudioManager.CAR_AUDIO_USAGE_ALARM:
Keun-young Park0727f952015-12-21 14:30:07 -0800269 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_ALARM_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800270 case CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION:
Keun-young Park0727f952015-12-21 14:30:07 -0800271 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NOTIFICATION_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800272 case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT:
273 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SAFETY_ALERT_FLAG;
274 case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND:
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800275 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SYSTEM_SOUND_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800276 case CarAudioManager.CAR_AUDIO_USAGE_DEFAULT:
Keun-young Park0727f952015-12-21 14:30:07 -0800277 return VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_UNKNOWN_FLAG;
Keun-young Park9ba6e8b2016-03-04 16:21:19 -0800278 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_BOTTOM:
279 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_CAR_PROXY:
Keun-young Park3cb89102016-05-05 13:16:03 -0700280 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_MEDIA_MUTE:
Keun-young Park9ba6e8b2016-03-04 16:21:19 -0800281 // internal tag not associated with any stream
282 return 0;
keunyoung5c7cb262015-10-19 10:47:45 -0700283 default:
284 Log.w(CarLog.TAG_AUDIO, "Unknown logical stream:" + logicalStream);
285 return 0;
286 }
keunyoungd32f4e62015-09-21 11:33:06 -0700287 }
288
Yao Chen75279c92016-05-06 14:41:37 -0700289 /**
290 * Converts car audio context type to car stream usage.
291 */
292 public static int carContextToCarUsage(int carContext) {
293 switch (carContext) {
294 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_MUSIC_FLAG:
295 return CarAudioManager.CAR_AUDIO_USAGE_MUSIC;
296 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NAVIGATION_FLAG:
297 return CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE;
298 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_ALARM_FLAG:
299 return CarAudioManager.CAR_AUDIO_USAGE_ALARM;
300 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_VOICE_COMMAND_FLAG:
301 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND;
302 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_AUX_AUDIO_FLAG:
303 return CarAudioManager.CAR_AUDIO_USAGE_MUSIC;
304 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CALL_FLAG:
305 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL;
306 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_CD_ROM_FLAG:
307 return CarAudioManager.CAR_AUDIO_USAGE_MUSIC;
308 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_NOTIFICATION_FLAG:
309 return CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION;
310 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_RADIO_FLAG:
311 return CarAudioManager.CAR_AUDIO_USAGE_RADIO;
312 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SAFETY_ALERT_FLAG:
313 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT;
314 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_SYSTEM_SOUND_FLAG:
315 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND;
316 case VehicleAudioContextFlag.VEHICLE_AUDIO_CONTEXT_UNKNOWN_FLAG:
317 return CarAudioManager.CAR_AUDIO_USAGE_DEFAULT;
318 default:
319 Log.w(CarLog.TAG_AUDIO, "Unknown car context:" + carContext);
320 return 0;
321 }
322 }
323
Keun-young Park1488ef22016-02-25 14:00:54 -0800324 public void requestAudioFocusChange(int request, int streams, int audioContexts) {
325 requestAudioFocusChange(request, streams, VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG, audioContexts);
keunyounga74b9ca2015-10-21 13:33:58 -0700326 }
327
Keun-young Park1488ef22016-02-25 14:00:54 -0800328 public void requestAudioFocusChange(int request, int streams, int extFocus, int audioContexts) {
329 int[] payload = { request, streams, extFocus, audioContexts };
Keun-young Parke78bf532016-04-25 18:59:22 -0700330 try {
331 mVehicleHal.getVehicleNetwork().setIntVectorProperty(
332 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS, payload);
333 } catch (ServiceSpecificException e) {
334 Log.e(CarLog.TAG_AUDIO, "Cannot write to VEHICLE_PROPERTY_AUDIO_FOCUS", e);
335 // focus timeout will reset it anyway
336 }
keunyoungd32f4e62015-09-21 11:33:06 -0700337 }
338
Yao Chenc4d442f2016-04-08 11:33:47 -0700339 public void setStreamVolume(int streamType, int index) {
340 int[] payload = {streamType, index, 0};
Keun-young Parke78bf532016-04-25 18:59:22 -0700341 try {
342 mVehicleHal.getVehicleNetwork().setIntVectorProperty(
343 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME, payload);
344 } catch (ServiceSpecificException e) {
345 Log.e(CarLog.TAG_AUDIO, "Cannot write to VEHICLE_PROPERTY_AUDIO_VOLUME", e);
346 //TODO should reset volume
347 }
Yao Chenc4d442f2016-04-08 11:33:47 -0700348 }
349
350 public int getStreamVolume(int stream) {
351 int[] volume = {stream, 0, 0};
352 VehiclePropValue streamVolume =
353 VehiclePropValueUtil.createIntVectorValue(
354 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME, volume, 0);
Keun-young Park021310d2016-04-25 21:09:39 -0700355 VehiclePropValue value;
356 try {
357 value = mVehicleHal.getVehicleNetwork().getProperty(streamVolume);
358 } catch (ServiceSpecificException e) {
359 Log.e(CarLog.TAG_AUDIO, "AUDIO_VOLUME not ready", e);
360 return 0;
361 }
Yao Chenc4d442f2016-04-08 11:33:47 -0700362
363 if (value.getInt32ValuesCount() != 3) {
364 Log.e(CarLog.TAG_AUDIO, "returned value not valid");
365 throw new IllegalStateException("Invalid preset returned from service: "
366 + value.getInt32ValuesList());
367 }
368
369 int retStreamNum = value.getInt32Values(0);
370 int retVolume = value.getInt32Values(1);
371 int retVolumeState = value.getInt32Values(2);
372
373 if (retStreamNum != stream) {
374 Log.e(CarLog.TAG_AUDIO, "Stream number is not the same: "
375 + stream + " vs " + retStreamNum);
376 throw new IllegalStateException("Stream number is not the same");
377 }
378 return retVolume;
379 }
380
keunyoung5c7cb262015-10-19 10:47:45 -0700381 public synchronized int getHwVariant() {
382 return mVariant;
383 }
384
keunyounga74b9ca2015-10-21 13:33:58 -0700385 public synchronized boolean isRadioExternal() {
386 VehiclePropConfig config = mProperties.get(
387 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT);
388 if (config == null) {
389 return true;
390 }
Keun-young Park0727f952015-12-21 14:30:07 -0800391 return (config.getConfigArray(0) &
Keun-young Park3057ebd2016-03-28 18:12:09 -0700392 VehicleAudioHwVariantConfigFlag.VEHICLE_AUDIO_HW_VARIANT_FLAG_INTERNAL_RADIO_FLAG)
keunyounga74b9ca2015-10-21 13:33:58 -0700393 == 0;
394 }
395
396 public synchronized boolean isFocusSupported() {
397 return isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS);
398 }
399
Keun-young Park07182c72016-03-18 18:01:29 -0700400 public synchronized boolean isAudioVolumeSupported() {
401 return isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
402 }
403
404 public synchronized int getSupportedAudioVolumeContexts() {
405 if (!isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME)) {
406 throw new IllegalStateException("VEHICLE_PROPERTY_AUDIO_VOLUME not supported");
407 }
408 VehiclePropConfig config = mProperties.get(
409 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
410 return config.getConfigArray(0);
411 }
412
413 /**
414 * Whether external audio module can memorize logical audio volumes or not.
415 * @return
416 */
417 public synchronized boolean isExternalAudioVolumePersistent() {
418 if (!isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME)) {
419 throw new IllegalStateException("VEHICLE_PROPERTY_AUDIO_VOLUME not supported");
420 }
421 VehiclePropConfig config = mProperties.get(
422 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
423 if (config.getConfigArray(0) == 0) { // physical streams only
424 return false;
425 }
426 if ((config.getConfigArray(1) &
427 VehicleAudioVolumeCapabilityFlag.VEHICLE_AUDIO_VOLUME_CAPABILITY_PERSISTENT_STORAGE)
428 != 0) {
429 return true;
430 }
431 return false;
432 }
433
434 public synchronized boolean isAudioVolumeLimitSupported() {
435 return isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT);
436 }
437
Keun-young Parkd36a9952016-05-24 10:03:59 -0700438 public synchronized boolean isAudioVolumeMasterOnly() {
439 if (!isPropertySupportedLocked(VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME)) {
440 throw new IllegalStateException("VEHICLE_PROPERTY_AUDIO_VOLUME not supported");
441 }
442 VehiclePropConfig config = mProperties.get(
443 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME);
444 if ((config.getConfigArray(1) &
445 VehicleAudioVolumeCapabilityFlag.VEHICLE_AUDIO_VOLUME_CAPABILITY_MASTER_VOLUME_ONLY)
446 != 0) {
447 return true;
448 }
449 return false;
450 }
451
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800452 /**
453 * Get the current audio focus state.
454 * @return 0: focusState, 1: streams, 2: externalFocus
455 */
456 public int[] getCurrentFocusState() {
457 if (!isFocusSupported()) {
458 return new int[] { VEHICLE_AUDIO_FOCUS_STATE_GAIN, 0xffffffff, 0};
459 }
Keun-young Parkba485482016-03-24 13:24:31 -0700460 try {
461 return mVehicleHal.getVehicleNetwork().getIntVectorProperty(
462 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS);
463 } catch (ServiceSpecificException e) {
464 Log.e(CarLog.TAG_AUDIO, "VEHICLE_PROPERTY_AUDIO_HW_VARIANT not ready", e);
465 return new int[] { VEHICLE_AUDIO_FOCUS_STATE_LOSS, 0x0, 0};
466 }
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800467 }
468
keunyounga74b9ca2015-10-21 13:33:58 -0700469 private boolean isPropertySupportedLocked(int property) {
470 VehiclePropConfig config = mProperties.get(property);
471 return config != null;
472 }
473
keunyoungd32f4e62015-09-21 11:33:06 -0700474 @Override
475 public synchronized void init() {
keunyounga74b9ca2015-10-21 13:33:58 -0700476 for (VehiclePropConfig config : mProperties.values()) {
477 if (VehicleHal.isPropertySubscribable(config)) {
478 mVehicleHal.subscribeProperty(this, config.getProp(), 0);
keunyoung5c7cb262015-10-19 10:47:45 -0700479 }
480 }
481 try {
482 mVariant = mVehicleHal.getVehicleNetwork().getIntProperty(
483 VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT);
484 } catch (IllegalArgumentException e) {
485 // no variant. Set to default, 0.
486 mVariant = 0;
Keun-young Parkba485482016-03-24 13:24:31 -0700487 } catch (ServiceSpecificException e) {
488 Log.e(CarLog.TAG_AUDIO, "VEHICLE_PROPERTY_AUDIO_HW_VARIANT not ready", e);
489 mVariant = 0;
keunyoungd32f4e62015-09-21 11:33:06 -0700490 }
491 }
492
493 @Override
494 public synchronized void release() {
keunyounga74b9ca2015-10-21 13:33:58 -0700495 for (VehiclePropConfig config : mProperties.values()) {
496 if (VehicleHal.isPropertySubscribable(config)) {
497 mVehicleHal.unsubscribeProperty(this, config.getProp());
keunyoung5c7cb262015-10-19 10:47:45 -0700498 }
keunyoungd32f4e62015-09-21 11:33:06 -0700499 }
keunyounga74b9ca2015-10-21 13:33:58 -0700500 mProperties.clear();
keunyoungd32f4e62015-09-21 11:33:06 -0700501 }
502
503 @Override
504 public synchronized List<VehiclePropConfig> takeSupportedProperties(
505 List<VehiclePropConfig> allProperties) {
keunyoungd32f4e62015-09-21 11:33:06 -0700506 for (VehiclePropConfig p : allProperties) {
507 switch (p.getProp()) {
508 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS:
keunyoungd32f4e62015-09-21 11:33:06 -0700509 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME:
keunyoung5c7cb262015-10-19 10:47:45 -0700510 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT:
keunyoung5c7cb262015-10-19 10:47:45 -0700511 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_HW_VARIANT:
keunyoungd32f4e62015-09-21 11:33:06 -0700512 case VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE:
keunyounga74b9ca2015-10-21 13:33:58 -0700513 mProperties.put(p.getProp(), p);
keunyoungd32f4e62015-09-21 11:33:06 -0700514 break;
515 }
516 }
keunyounga74b9ca2015-10-21 13:33:58 -0700517 return new LinkedList<VehiclePropConfig>(mProperties.values());
keunyoungd32f4e62015-09-21 11:33:06 -0700518 }
519
520 @Override
521 public void handleHalEvents(List<VehiclePropValue> values) {
Keun-young Park07182c72016-03-18 18:01:29 -0700522 AudioHalFocusListener focusListener = null;
523 AudioHalVolumeListener volumeListener = null;
keunyoungd32f4e62015-09-21 11:33:06 -0700524 synchronized (this) {
Keun-young Park07182c72016-03-18 18:01:29 -0700525 focusListener = mFocusListener;
526 volumeListener = mVolumeListener;
keunyoungd32f4e62015-09-21 11:33:06 -0700527 }
Keun-young Park6b3f7192016-03-25 18:41:49 -0700528 dispatchEventToListener(focusListener, volumeListener, values);
Keun-young Park07182c72016-03-18 18:01:29 -0700529 }
530
531 private void dispatchEventToListener(AudioHalFocusListener focusListener,
532 AudioHalVolumeListener volumeListener,
533 List<VehiclePropValue> values) {
keunyoungd32f4e62015-09-21 11:33:06 -0700534 for (VehiclePropValue v : values) {
535 switch (v.getProp()) {
536 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_FOCUS: {
keunyounga74b9ca2015-10-21 13:33:58 -0700537 int focusState = v.getInt32Values(
538 VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_FOCUS);
539 int streams = v.getInt32Values(
540 VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_STREAMS);
541 int externalFocus = v.getInt32Values(
542 VehicleAudioFocusIndex.VEHICLE_AUDIO_FOCUS_INDEX_EXTERNAL_FOCUS_STATE);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700543 if (focusListener != null) {
544 focusListener.onFocusChange(focusState, streams, externalFocus);
545 }
546 } break;
547 case VehicleNetworkConsts.VEHICLE_PROPERTY_INTERNAL_AUDIO_STREAM_STATE: {
548 int state = v.getInt32Values(
549 VehicleAudioStreamStateIndex.VEHICLE_AUDIO_STREAM_STATE_INDEX_STATE);
550 int streamNum = v.getInt32Values(
551 VehicleAudioStreamStateIndex.VEHICLE_AUDIO_STREAM_STATE_INDEX_STREAM);
552 if (focusListener != null) {
553 focusListener.onStreamStatusChange(streamNum, state);
554 }
keunyoungd32f4e62015-09-21 11:33:06 -0700555 } break;
556 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME: {
keunyounga74b9ca2015-10-21 13:33:58 -0700557 int volume = v.getInt32Values(
558 VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_VOLUME);
559 int streamNum = v.getInt32Values(
560 VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STREAM);
561 int volumeState = v.getInt32Values(
562 VehicleAudioVolumeIndex.VEHICLE_AUDIO_VOLUME_INDEX_STATE);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700563 if (volumeListener != null) {
564 volumeListener.onVolumeChange(streamNum, volume, volumeState);
565 }
keunyoung5c7cb262015-10-19 10:47:45 -0700566 } break;
567 case VehicleNetworkConsts.VEHICLE_PROPERTY_AUDIO_VOLUME_LIMIT: {
Keun-young Park07182c72016-03-18 18:01:29 -0700568 int stream = v.getInt32Values(
569 VehicleAudioVolumeLimitIndex.VEHICLE_AUDIO_VOLUME_LIMIT_INDEX_STREAM);
570 int maxVolume = v.getInt32Values(
571 VehicleAudioVolumeLimitIndex.VEHICLE_AUDIO_VOLUME_LIMIT_INDEX_MAX_VOLUME);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700572 if (volumeListener != null) {
573 volumeListener.onVolumeLimitChange(stream, maxVolume);
574 }
keunyoungd32f4e62015-09-21 11:33:06 -0700575 } break;
576 }
577 }
Keun-young Park07182c72016-03-18 18:01:29 -0700578 values.clear();
keunyoungd32f4e62015-09-21 11:33:06 -0700579 }
580
581 @Override
582 public void dump(PrintWriter writer) {
keunyoung5c7cb262015-10-19 10:47:45 -0700583 writer.println("*Audio HAL*");
584 writer.println(" audio H/W variant:" + mVariant);
keunyounga74b9ca2015-10-21 13:33:58 -0700585 writer.println(" Supported properties");
586 VehicleHal.dumpProperties(writer, mProperties.values());
keunyoungd32f4e62015-09-21 11:33:06 -0700587 }
588
589}