blob: 14b83197e6b12cfe935addddd2d686ebc94bfe52 [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;
Pavel Maltsevde714b72017-03-24 12:46:40 -070023import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_STREAM_STATE;
Pavel Maltsevcfe93102017-02-02 12:38:08 -080024import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_VOLUME;
25import static android.hardware.automotive.vehicle.V2_0.VehicleProperty.AUDIO_VOLUME_LIMIT;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070026import static com.android.car.CarServiceUtils.toIntArray;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070027
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 Maltsevde714b72017-03-24 12:46:40 -070032import android.hardware.automotive.vehicle.V2_0.SubscribeFlags;
Pavel Maltsevcfe93102017-02-02 12:38:08 -080033import android.hardware.automotive.vehicle.V2_0.VehicleAudioContextFlag;
34import android.hardware.automotive.vehicle.V2_0.VehicleAudioExtFocusFlag;
35import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusIndex;
36import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusRequest;
37import android.hardware.automotive.vehicle.V2_0.VehicleAudioFocusState;
38import android.hardware.automotive.vehicle.V2_0.VehicleAudioHwVariantConfigFlag;
39import android.hardware.automotive.vehicle.V2_0.VehicleAudioRoutingPolicyIndex;
40import android.hardware.automotive.vehicle.V2_0.VehicleAudioVolumeCapabilityFlag;
41import android.hardware.automotive.vehicle.V2_0.VehicleAudioVolumeIndex;
42import android.hardware.automotive.vehicle.V2_0.VehicleAudioVolumeLimitIndex;
43import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig;
44import android.hardware.automotive.vehicle.V2_0.VehiclePropValue;
45import android.hardware.automotive.vehicle.V2_0.VehicleProperty;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070046import android.text.TextUtils;
keunyoung5c7cb262015-10-19 10:47:45 -070047import android.util.Log;
48
49import com.android.car.AudioRoutingPolicy;
Keun-young Park9ba6e8b2016-03-04 16:21:19 -080050import com.android.car.CarAudioAttributesUtil;
keunyoung5c7cb262015-10-19 10:47:45 -070051import com.android.car.CarLog;
keunyoungd32f4e62015-09-21 11:33:06 -070052
53import java.io.PrintWriter;
Pavel Maltsev0d07c762016-11-03 16:40:15 -070054import java.util.ArrayList;
55import java.util.Arrays;
56import java.util.Collection;
keunyounga74b9ca2015-10-21 13:33:58 -070057import java.util.HashMap;
keunyoungd32f4e62015-09-21 11:33:06 -070058import java.util.List;
Keun-young Park4c6834a2016-06-28 12:58:23 -070059import java.util.Map;
keunyoungd32f4e62015-09-21 11:33:06 -070060
61public class AudioHalService extends HalServiceBase {
keunyounga74b9ca2015-10-21 13:33:58 -070062 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_INVALID = -1;
keunyoungd32f4e62015-09-21 11:33:06 -070063 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070064 VehicleAudioFocusRequest.REQUEST_GAIN;
keunyoungd32f4e62015-09-21 11:33:06 -070065 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070066 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070067 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_MAY_DUCK =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070068 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_MAY_DUCK;
Keun-young Park32b63822016-08-02 11:22:29 -070069 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_GAIN_TRANSIENT_NO_DUCK =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070070 VehicleAudioFocusRequest.REQUEST_GAIN_TRANSIENT_NO_DUCK;
keunyoungd32f4e62015-09-21 11:33:06 -070071 public static final int VEHICLE_AUDIO_FOCUS_REQUEST_RELEASE =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070072 VehicleAudioFocusRequest.REQUEST_RELEASE;
keunyoungd32f4e62015-09-21 11:33:06 -070073
keunyounga74b9ca2015-10-21 13:33:58 -070074 public static final int VEHICLE_AUDIO_FOCUS_STATE_INVALID = -1;
keunyoungd32f4e62015-09-21 11:33:06 -070075 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070076 VehicleAudioFocusState.STATE_GAIN;
keunyoungd32f4e62015-09-21 11:33:06 -070077 public static final int VEHICLE_AUDIO_FOCUS_STATE_GAIN_TRANSIENT =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070078 VehicleAudioFocusState.STATE_GAIN_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070079 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_CAN_DUCK =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070080 VehicleAudioFocusState.STATE_LOSS_TRANSIENT_CAN_DUCK;
keunyoungd32f4e62015-09-21 11:33:06 -070081 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070082 VehicleAudioFocusState.STATE_LOSS_TRANSIENT;
keunyoungd32f4e62015-09-21 11:33:06 -070083 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070084 VehicleAudioFocusState.STATE_LOSS;
keunyoungd32f4e62015-09-21 11:33:06 -070085 public static final int VEHICLE_AUDIO_FOCUS_STATE_LOSS_TRANSIENT_EXLCUSIVE =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070086 VehicleAudioFocusState.STATE_LOSS_TRANSIENT_EXLCUSIVE;
keunyoungd32f4e62015-09-21 11:33:06 -070087
Pavel Maltsevde714b72017-03-24 12:46:40 -070088 public static final int VEHICLE_AUDIO_STREAM_STATE_STOPPED = 0;
89 public static final int VEHICLE_AUDIO_STREAM_STATE_STARTED = 1;
keunyoungd32f4e62015-09-21 11:33:06 -070090
keunyounga74b9ca2015-10-21 13:33:58 -070091 public static final int VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070092 VehicleAudioExtFocusFlag.NONE_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -070093 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PERMANENT_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070094 VehicleAudioExtFocusFlag.PERMANENT_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -070095 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_TRANSIENT_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070096 VehicleAudioExtFocusFlag.TRANSIENT_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -070097 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_PLAY_ONLY_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -070098 VehicleAudioExtFocusFlag.PLAY_ONLY_FLAG;
Keun-young Park3cb89102016-05-05 13:16:03 -070099 public static final int VEHICLE_AUDIO_EXT_FOCUS_CAR_MUTE_MEDIA_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700100 VehicleAudioExtFocusFlag.MUTE_MEDIA_FLAG;
keunyounga74b9ca2015-10-21 13:33:58 -0700101
keunyoungd32f4e62015-09-21 11:33:06 -0700102 public static final int STREAM_NUM_DEFAULT = 0;
103
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800104 public static final int FOCUS_STATE_ARRAY_INDEX_STATE = 0;
105 public static final int FOCUS_STATE_ARRAY_INDEX_STREAMS = 1;
106 public static final int FOCUS_STATE_ARRAY_INDEX_EXTERNAL_FOCUS = 2;
107
Keun-young Park1488ef22016-02-25 14:00:54 -0800108 public static final int AUDIO_CONTEXT_MUSIC_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700109 VehicleAudioContextFlag.MUSIC_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800110 public static final int AUDIO_CONTEXT_NAVIGATION_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700111 VehicleAudioContextFlag.NAVIGATION_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800112 public static final int AUDIO_CONTEXT_VOICE_COMMAND_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700113 VehicleAudioContextFlag.VOICE_COMMAND_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800114 public static final int AUDIO_CONTEXT_CALL_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700115 VehicleAudioContextFlag.CALL_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800116 public static final int AUDIO_CONTEXT_ALARM_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700117 VehicleAudioContextFlag.ALARM_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800118 public static final int AUDIO_CONTEXT_NOTIFICATION_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700119 VehicleAudioContextFlag.NOTIFICATION_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800120 public static final int AUDIO_CONTEXT_UNKNOWN_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700121 VehicleAudioContextFlag.UNKNOWN_FLAG;
Keun-young Park1488ef22016-02-25 14:00:54 -0800122 public static final int AUDIO_CONTEXT_SAFETY_ALERT_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700123 VehicleAudioContextFlag.SAFETY_ALERT_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800124 public static final int AUDIO_CONTEXT_RADIO_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700125 VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800126 public static final int AUDIO_CONTEXT_CD_ROM_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700127 VehicleAudioContextFlag.CD_ROM_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800128 public static final int AUDIO_CONTEXT_AUX_AUDIO_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700129 VehicleAudioContextFlag.AUX_AUDIO_FLAG;
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800130 public static final int AUDIO_CONTEXT_SYSTEM_SOUND_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700131 VehicleAudioContextFlag.SYSTEM_SOUND_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700132 public static final int AUDIO_CONTEXT_EXT_SOURCE_FLAG =
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700133 VehicleAudioContextFlag.EXT_SOURCE_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
Keun-young Park32b63822016-08-02 11:22:29 -0700146 * @param streamNumber stream number like 0, 1, ...
147 * @param streamActive Whether the stream is active or not.
Keun-young Park07182c72016-03-18 18:01:29 -0700148 */
Keun-young Park32b63822016-08-02 11:22:29 -0700149 void onStreamStatusChange(int streamNumber, boolean streamActive);
Keun-young Park07182c72016-03-18 18:01:29 -0700150 }
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
Vitalii Tomkiv1b1247b2016-09-30 11:27:19 -0700168 private static final boolean DBG = false;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700169
keunyoungd32f4e62015-09-21 11:33:06 -0700170 private final VehicleHal mVehicleHal;
Keun-young Park07182c72016-03-18 18:01:29 -0700171 private AudioHalFocusListener mFocusListener;
172 private AudioHalVolumeListener mVolumeListener;
keunyoung5c7cb262015-10-19 10:47:45 -0700173 private int mVariant;
174
keunyounga74b9ca2015-10-21 13:33:58 -0700175 private final HashMap<Integer, VehiclePropConfig> mProperties = new HashMap<>();
176
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800177 private OnParameterChangeListener mOnParameterChangeListener;
178
keunyoungd32f4e62015-09-21 11:33:06 -0700179 public AudioHalService(VehicleHal vehicleHal) {
180 mVehicleHal = vehicleHal;
181 }
182
Keun-young Park6b3f7192016-03-25 18:41:49 -0700183 public synchronized void setFocusListener(AudioHalFocusListener focusListener) {
184 mFocusListener = focusListener;
Keun-young Park07182c72016-03-18 18:01:29 -0700185 }
186
Keun-young Park6b3f7192016-03-25 18:41:49 -0700187 public synchronized void setVolumeListener(AudioHalVolumeListener volumeListener) {
188 mVolumeListener = volumeListener;
keunyoung5c7cb262015-10-19 10:47:45 -0700189 }
190
191 public void setAudioRoutingPolicy(AudioRoutingPolicy policy) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700192 if (!mVehicleHal.isPropertySupported(VehicleProperty.AUDIO_ROUTING_POLICY)) {
keunyoung5c7cb262015-10-19 10:47:45 -0700193 Log.w(CarLog.TAG_AUDIO,
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700194 "Vehicle HAL did not implement VehicleProperty.AUDIO_ROUTING_POLICY");
keunyoung5c7cb262015-10-19 10:47:45 -0700195 return;
196 }
197 int[] policyToSet = new int[2];
198 for (int i = 0; i < policy.getPhysicalStreamsCount(); i++) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700199 policyToSet[VehicleAudioRoutingPolicyIndex.STREAM] = 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 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700204 policyToSet[VehicleAudioRoutingPolicyIndex.CONTEXTS] = contexts;
Keun-young Parke78bf532016-04-25 18:59:22 -0700205 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700206 mVehicleHal.set(AUDIO_ROUTING_POLICY).to(policyToSet);
207 } catch (PropertyTimeoutException e) {
208 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_ROUTING_POLICY", e);
Keun-young Parke78bf532016-04-25 18:59:22 -0700209 }
keunyoung5c7cb262015-10-19 10:47:45 -0700210 }
211 }
212
Keun-young Park1488ef22016-02-25 14:00:54 -0800213 /**
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700214 * Returns the volume limits of a stream. Returns null if max value wasn't defined for
215 * AUDIO_VOLUME property.
Yao Chenc4d442f2016-04-08 11:33:47 -0700216 */
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700217 @Nullable
218 public synchronized Integer getStreamMaxVolume(int stream) {
219 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_VOLUME);
220 if (config == null) {
221 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Yao Chenc4d442f2016-04-08 11:33:47 -0700222 }
223 int supportedContext = getSupportedAudioVolumeContexts();
Yao Chenc4d442f2016-04-08 11:33:47 -0700224
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700225 int MAX_VALUES_FIRST_ELEMENT_INDEX = 4;
226 ArrayList<Integer> maxValues = new ArrayList<>();
227 for (int i = MAX_VALUES_FIRST_ELEMENT_INDEX; i < config.configArray.size(); i++) {
228 maxValues.add(config.configArray.get(i));
Yao Chenc4d442f2016-04-08 11:33:47 -0700229 }
230
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700231 Integer result = null;
Yao Chenc4d442f2016-04-08 11:33:47 -0700232 if (supportedContext != 0) {
233 int index = VehicleZoneUtil.zoneToIndex(supportedContext, stream);
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700234 if (index < maxValues.size()) {
235 result = maxValues.get(index);
Yao Chenc4d442f2016-04-08 11:33:47 -0700236 }
237 } else {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700238 if (stream < maxValues.size()) {
239 result = maxValues.get(stream);
Yao Chenc4d442f2016-04-08 11:33:47 -0700240 }
241 }
242
243 if (result == null) {
244 Log.e(CarLog.TAG_AUDIO, "No min/max volume found in vehicle" +
245 " prop config for stream: " + stream);
246 }
247
248 return result;
249 }
250
251 /**
Keun-young Park1488ef22016-02-25 14:00:54 -0800252 * Convert car audio manager stream type (usage) into audio context type.
253 */
254 public static int logicalStreamToHalContextType(int logicalStream) {
Keun-young Park4c6834a2016-06-28 12:58:23 -0700255 return logicalStreamWithExtTypeToHalContextType(logicalStream, null);
256 }
257
258 public static int logicalStreamWithExtTypeToHalContextType(int logicalStream, String extType) {
keunyoung5c7cb262015-10-19 10:47:45 -0700259 switch (logicalStream) {
Keun-young Parkd8c22f22016-03-03 17:16:51 -0800260 case CarAudioManager.CAR_AUDIO_USAGE_RADIO:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700261 return VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800262 case CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700263 return VehicleAudioContextFlag.CALL_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800264 case CarAudioManager.CAR_AUDIO_USAGE_MUSIC:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700265 return VehicleAudioContextFlag.MUSIC_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800266 case CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700267 return VehicleAudioContextFlag.NAVIGATION_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800268 case CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700269 return VehicleAudioContextFlag.VOICE_COMMAND_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800270 case CarAudioManager.CAR_AUDIO_USAGE_ALARM:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700271 return VehicleAudioContextFlag.ALARM_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800272 case CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700273 return VehicleAudioContextFlag.NOTIFICATION_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800274 case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700275 return VehicleAudioContextFlag.SAFETY_ALERT_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800276 case CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700277 return VehicleAudioContextFlag.SYSTEM_SOUND_FLAG;
Keun-young Park5672e852016-02-09 19:53:48 -0800278 case CarAudioManager.CAR_AUDIO_USAGE_DEFAULT:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700279 return VehicleAudioContextFlag.UNKNOWN_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700280 case CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE:
281 if (extType != null) {
282 switch (extType) {
283 case CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_CD_DVD:
284 return AudioHalService.AUDIO_CONTEXT_CD_ROM_FLAG;
285 case CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_AUX_IN0:
286 case CarAudioManager.CAR_EXTERNAL_SOURCE_TYPE_AUX_IN1:
287 return AudioHalService.AUDIO_CONTEXT_AUX_AUDIO_FLAG;
288 default:
289 if (extType.startsWith("RADIO_")) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700290 return VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700291 } else {
292 return AudioHalService.AUDIO_CONTEXT_EXT_SOURCE_FLAG;
293 }
294 }
295 } else { // no external source specified. fall back to radio
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700296 return VehicleAudioContextFlag.RADIO_FLAG;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700297 }
Keun-young Park9ba6e8b2016-03-04 16:21:19 -0800298 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_BOTTOM:
299 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_CAR_PROXY:
Keun-young Park3cb89102016-05-05 13:16:03 -0700300 case CarAudioAttributesUtil.CAR_AUDIO_USAGE_CARSERVICE_MEDIA_MUTE:
Keun-young Park9ba6e8b2016-03-04 16:21:19 -0800301 // internal tag not associated with any stream
302 return 0;
keunyoung5c7cb262015-10-19 10:47:45 -0700303 default:
304 Log.w(CarLog.TAG_AUDIO, "Unknown logical stream:" + logicalStream);
305 return 0;
306 }
keunyoungd32f4e62015-09-21 11:33:06 -0700307 }
308
Yao Chen75279c92016-05-06 14:41:37 -0700309 /**
310 * Converts car audio context type to car stream usage.
311 */
312 public static int carContextToCarUsage(int carContext) {
313 switch (carContext) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700314 case VehicleAudioContextFlag.MUSIC_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700315 return CarAudioManager.CAR_AUDIO_USAGE_MUSIC;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700316 case VehicleAudioContextFlag.NAVIGATION_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700317 return CarAudioManager.CAR_AUDIO_USAGE_NAVIGATION_GUIDANCE;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700318 case VehicleAudioContextFlag.ALARM_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700319 return CarAudioManager.CAR_AUDIO_USAGE_ALARM;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700320 case VehicleAudioContextFlag.VOICE_COMMAND_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700321 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_COMMAND;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700322 case VehicleAudioContextFlag.AUX_AUDIO_FLAG:
Keun-young Park4c6834a2016-06-28 12:58:23 -0700323 return CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700324 case VehicleAudioContextFlag.CALL_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700325 return CarAudioManager.CAR_AUDIO_USAGE_VOICE_CALL;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700326 case VehicleAudioContextFlag.CD_ROM_FLAG:
Keun-young Park4c6834a2016-06-28 12:58:23 -0700327 return CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700328 case VehicleAudioContextFlag.NOTIFICATION_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700329 return CarAudioManager.CAR_AUDIO_USAGE_NOTIFICATION;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700330 case VehicleAudioContextFlag.RADIO_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700331 return CarAudioManager.CAR_AUDIO_USAGE_RADIO;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700332 case VehicleAudioContextFlag.SAFETY_ALERT_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700333 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SAFETY_ALERT;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700334 case VehicleAudioContextFlag.SYSTEM_SOUND_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700335 return CarAudioManager.CAR_AUDIO_USAGE_SYSTEM_SOUND;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700336 case VehicleAudioContextFlag.UNKNOWN_FLAG:
Yao Chen75279c92016-05-06 14:41:37 -0700337 return CarAudioManager.CAR_AUDIO_USAGE_DEFAULT;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700338 case VehicleAudioContextFlag.EXT_SOURCE_FLAG:
Keun-young Park4c6834a2016-06-28 12:58:23 -0700339 return CarAudioManager.CAR_AUDIO_USAGE_EXTERNAL_AUDIO_SOURCE;
Yao Chen75279c92016-05-06 14:41:37 -0700340 default:
341 Log.w(CarLog.TAG_AUDIO, "Unknown car context:" + carContext);
342 return 0;
343 }
344 }
345
Keun-young Park1488ef22016-02-25 14:00:54 -0800346 public void requestAudioFocusChange(int request, int streams, int audioContexts) {
347 requestAudioFocusChange(request, streams, VEHICLE_AUDIO_EXT_FOCUS_NONE_FLAG, audioContexts);
keunyounga74b9ca2015-10-21 13:33:58 -0700348 }
349
Keun-young Park1488ef22016-02-25 14:00:54 -0800350 public void requestAudioFocusChange(int request, int streams, int extFocus, int audioContexts) {
351 int[] payload = { request, streams, extFocus, audioContexts };
Keun-young Parke78bf532016-04-25 18:59:22 -0700352 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700353 mVehicleHal.set(AUDIO_FOCUS).to(payload);
354 } catch (PropertyTimeoutException e) {
355 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_FOCUS", e);
Keun-young Parke78bf532016-04-25 18:59:22 -0700356 // focus timeout will reset it anyway
357 }
keunyoungd32f4e62015-09-21 11:33:06 -0700358 }
359
Yao Chenc4d442f2016-04-08 11:33:47 -0700360 public void setStreamVolume(int streamType, int index) {
361 int[] payload = {streamType, index, 0};
Keun-young Parke78bf532016-04-25 18:59:22 -0700362 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700363 mVehicleHal.set(VehicleProperty.AUDIO_VOLUME).to(payload);
364 } catch (PropertyTimeoutException e) {
365 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_VOLUME", e);
Keun-young Parkf9215202016-10-10 12:34:08 -0700366 //TODO should reset volume, bug: 32096870
Keun-young Parke78bf532016-04-25 18:59:22 -0700367 }
Yao Chenc4d442f2016-04-08 11:33:47 -0700368 }
369
370 public int getStreamVolume(int stream) {
371 int[] volume = {stream, 0, 0};
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700372 VehiclePropValue requestedStreamVolume = new VehiclePropValue();
373 requestedStreamVolume.prop = VehicleProperty.AUDIO_VOLUME;
374 requestedStreamVolume.value.int32Values.addAll(Arrays.asList(stream, 0 , 0));
375 VehiclePropValue propValue;
Keun-young Park021310d2016-04-25 21:09:39 -0700376 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700377 propValue = mVehicleHal.get(requestedStreamVolume);
378 } catch (PropertyTimeoutException e) {
379 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_VOLUME not ready", e);
Keun-young Park021310d2016-04-25 21:09:39 -0700380 return 0;
381 }
Yao Chenc4d442f2016-04-08 11:33:47 -0700382
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700383 if (propValue.value.int32Values.size() != 3) {
Yao Chenc4d442f2016-04-08 11:33:47 -0700384 Log.e(CarLog.TAG_AUDIO, "returned value not valid");
385 throw new IllegalStateException("Invalid preset returned from service: "
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700386 + Arrays.toString(propValue.value.int32Values.toArray()));
Yao Chenc4d442f2016-04-08 11:33:47 -0700387 }
388
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700389 int retStreamNum = propValue.value.int32Values.get(0);
390 int retVolume = propValue.value.int32Values.get(1);
391 int retVolumeState = propValue.value.int32Values.get(2);
Yao Chenc4d442f2016-04-08 11:33:47 -0700392
393 if (retStreamNum != stream) {
394 Log.e(CarLog.TAG_AUDIO, "Stream number is not the same: "
395 + stream + " vs " + retStreamNum);
396 throw new IllegalStateException("Stream number is not the same");
397 }
398 return retVolume;
399 }
400
keunyoung5c7cb262015-10-19 10:47:45 -0700401 public synchronized int getHwVariant() {
402 return mVariant;
403 }
404
keunyounga74b9ca2015-10-21 13:33:58 -0700405 public synchronized boolean isRadioExternal() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700406 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_HW_VARIANT);
keunyounga74b9ca2015-10-21 13:33:58 -0700407 if (config == null) {
408 return true;
409 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700410 return (config.configArray.get(0)
411 & VehicleAudioHwVariantConfigFlag.INTERNAL_RADIO_FLAG) == 0;
keunyounga74b9ca2015-10-21 13:33:58 -0700412 }
413
414 public synchronized boolean isFocusSupported() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700415 return isPropertySupportedLocked(AUDIO_FOCUS);
keunyounga74b9ca2015-10-21 13:33:58 -0700416 }
417
Keun-young Park07182c72016-03-18 18:01:29 -0700418 public synchronized boolean isAudioVolumeSupported() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700419 return isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME);
Keun-young Park07182c72016-03-18 18:01:29 -0700420 }
421
422 public synchronized int getSupportedAudioVolumeContexts() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700423 if (!isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME)) {
424 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Keun-young Park07182c72016-03-18 18:01:29 -0700425 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700426 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_VOLUME);
427 return config.configArray.get(0);
Keun-young Park07182c72016-03-18 18:01:29 -0700428 }
429
430 /**
431 * Whether external audio module can memorize logical audio volumes or not.
432 * @return
433 */
434 public synchronized boolean isExternalAudioVolumePersistent() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700435 if (!isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME)) {
436 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Keun-young Park07182c72016-03-18 18:01:29 -0700437 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700438 VehiclePropConfig config = mProperties.get(VehicleProperty.AUDIO_VOLUME);
439 if (config.configArray.get(0) == 0) { // physical streams only
Keun-young Park07182c72016-03-18 18:01:29 -0700440 return false;
441 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700442 if ((config.configArray.get(1)
443 & VehicleAudioVolumeCapabilityFlag.PERSISTENT_STORAGE) != 0) {
Keun-young Park07182c72016-03-18 18:01:29 -0700444 return true;
445 }
446 return false;
447 }
448
449 public synchronized boolean isAudioVolumeLimitSupported() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700450 return isPropertySupportedLocked(AUDIO_VOLUME_LIMIT);
Keun-young Park07182c72016-03-18 18:01:29 -0700451 }
452
Keun-young Parkd36a9952016-05-24 10:03:59 -0700453 public synchronized boolean isAudioVolumeMasterOnly() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700454 if (!isPropertySupportedLocked(VehicleProperty.AUDIO_VOLUME)) {
455 throw new IllegalStateException("VehicleProperty.AUDIO_VOLUME not supported");
Keun-young Parkd36a9952016-05-24 10:03:59 -0700456 }
457 VehiclePropConfig config = mProperties.get(
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700458 AUDIO_VOLUME);
459 if ((config.configArray.get(1) &
460 VehicleAudioVolumeCapabilityFlag.MASTER_VOLUME_ONLY)
Keun-young Parkd36a9952016-05-24 10:03:59 -0700461 != 0) {
462 return true;
463 }
464 return false;
465 }
466
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800467 /**
468 * Get the current audio focus state.
469 * @return 0: focusState, 1: streams, 2: externalFocus
470 */
471 public int[] getCurrentFocusState() {
472 if (!isFocusSupported()) {
473 return new int[] { VEHICLE_AUDIO_FOCUS_STATE_GAIN, 0xffffffff, 0};
474 }
Keun-young Parkba485482016-03-24 13:24:31 -0700475 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700476 VehiclePropValue propValue = mVehicleHal.get(VehicleProperty.AUDIO_FOCUS);
477 return toIntArray(propValue.value.int32Values);
478 } catch (PropertyTimeoutException e) {
479 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_HW_VARIANT not ready", e);
Keun-young Parkba485482016-03-24 13:24:31 -0700480 return new int[] { VEHICLE_AUDIO_FOCUS_STATE_LOSS, 0x0, 0};
481 }
Keun-young Park1fdf91c2016-01-21 10:17:41 -0800482 }
483
Keun-young Park4c6834a2016-06-28 12:58:23 -0700484 public static class ExtRoutingSourceInfo {
485 /** Represents an external route which will not disable any physical stream in android side.
486 */
487 public static final int NO_DISABLED_PHYSICAL_STREAM = -1;
488
489 /** Bit position of this source in vhal */
490 public final int bitPosition;
491 /**
492 * Physical stream replaced by this routing. will be {@link #NO_DISABLED_PHYSICAL_STREAM}
493 * if no physical stream for android is replaced by this routing.
494 */
495 public final int physicalStreamNumber;
496
497 public ExtRoutingSourceInfo(int bitPosition, int physycalStreamNumber) {
498 this.bitPosition = bitPosition;
499 this.physicalStreamNumber = physycalStreamNumber;
500 }
501
502 @Override
503 public String toString() {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700504 return "[bitPosition=" + bitPosition + ", physicalStreamNumber="
Keun-young Park4c6834a2016-06-28 12:58:23 -0700505 + physicalStreamNumber + "]";
506 }
507 }
508
509 /**
510 * Get external audio routing types from AUDIO_EXT_ROUTING_HINT property.
511 *
512 * @return null if AUDIO_EXT_ROUTING_HINT is not supported.
513 */
514 public Map<String, ExtRoutingSourceInfo> getExternalAudioRoutingTypes() {
515 VehiclePropConfig config;
516 synchronized (this) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700517 if (!isPropertySupportedLocked(AUDIO_EXT_ROUTING_HINT)) {
518 if (DBG) {
519 Log.i(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT is not supported");
520 }
Keun-young Park4c6834a2016-06-28 12:58:23 -0700521 return null;
522 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700523 config = mProperties.get(AUDIO_EXT_ROUTING_HINT);
Keun-young Park4c6834a2016-06-28 12:58:23 -0700524 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700525 if (TextUtils.isEmpty(config.configString)) {
526 Log.w(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT with empty config string");
Keun-young Park4c6834a2016-06-28 12:58:23 -0700527 return null;
528 }
529 Map<String, ExtRoutingSourceInfo> routingTypes = new HashMap<>();
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700530 String configString = config.configString;
Keun-young Park4c6834a2016-06-28 12:58:23 -0700531 if (DBG) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700532 Log.i(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT config string:" + configString);
Keun-young Park4c6834a2016-06-28 12:58:23 -0700533 }
534 String[] routes = configString.split(",");
535 for (String routeString : routes) {
536 String[] tokens = routeString.split(":");
537 int bitPosition = 0;
538 String name = null;
539 int physicalStreamNumber = ExtRoutingSourceInfo.NO_DISABLED_PHYSICAL_STREAM;
540 if (tokens.length == 2) {
541 bitPosition = Integer.parseInt(tokens[0]);
542 name = tokens[1];
543 } else if (tokens.length == 3) {
544 bitPosition = Integer.parseInt(tokens[0]);
545 name = tokens[1];
546 physicalStreamNumber = Integer.parseInt(tokens[2]);
547 } else {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700548 Log.w(CarLog.TAG_AUDIO, "AUDIO_EXT_ROUTING_HINT has wrong entry:" +
Keun-young Park4c6834a2016-06-28 12:58:23 -0700549 routeString);
550 continue;
551 }
552 routingTypes.put(name, new ExtRoutingSourceInfo(bitPosition, physicalStreamNumber));
553 }
554 return routingTypes;
555 }
556
557 public void setExternalRoutingSource(int[] externalRoutings) {
558 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700559 mVehicleHal.set(AUDIO_EXT_ROUTING_HINT).to(externalRoutings);
560 } catch (PropertyTimeoutException e) {
561 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_EXT_ROUTING_HINT", e);
Keun-young Park4c6834a2016-06-28 12:58:23 -0700562 }
563 }
564
keunyounga74b9ca2015-10-21 13:33:58 -0700565 private boolean isPropertySupportedLocked(int property) {
566 VehiclePropConfig config = mProperties.get(property);
567 return config != null;
568 }
569
keunyoungd32f4e62015-09-21 11:33:06 -0700570 @Override
571 public synchronized void init() {
keunyounga74b9ca2015-10-21 13:33:58 -0700572 for (VehiclePropConfig config : mProperties.values()) {
573 if (VehicleHal.isPropertySubscribable(config)) {
Pavel Maltsevde714b72017-03-24 12:46:40 -0700574 int subsribeFlag = SubscribeFlags.HAL_EVENT;
575 if (AUDIO_STREAM_STATE == config.prop) {
576 subsribeFlag |= SubscribeFlags.SET_CALL;
577 }
578 mVehicleHal.subscribeProperty(this, config.prop, 0, subsribeFlag);
keunyoung5c7cb262015-10-19 10:47:45 -0700579 }
580 }
581 try {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700582 mVariant = mVehicleHal.get(int.class, AUDIO_HW_VARIANT);
keunyoung5c7cb262015-10-19 10:47:45 -0700583 } catch (IllegalArgumentException e) {
584 // no variant. Set to default, 0.
585 mVariant = 0;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700586 } catch (PropertyTimeoutException e) {
587 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_HW_VARIANT not ready", e);
Keun-young Parkba485482016-03-24 13:24:31 -0700588 mVariant = 0;
keunyoungd32f4e62015-09-21 11:33:06 -0700589 }
590 }
591
592 @Override
593 public synchronized void release() {
keunyounga74b9ca2015-10-21 13:33:58 -0700594 for (VehiclePropConfig config : mProperties.values()) {
595 if (VehicleHal.isPropertySubscribable(config)) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700596 mVehicleHal.unsubscribeProperty(this, config.prop);
keunyoung5c7cb262015-10-19 10:47:45 -0700597 }
keunyoungd32f4e62015-09-21 11:33:06 -0700598 }
keunyounga74b9ca2015-10-21 13:33:58 -0700599 mProperties.clear();
keunyoungd32f4e62015-09-21 11:33:06 -0700600 }
601
602 @Override
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700603 public synchronized Collection<VehiclePropConfig> takeSupportedProperties(
604 Collection<VehiclePropConfig> allProperties) {
keunyoungd32f4e62015-09-21 11:33:06 -0700605 for (VehiclePropConfig p : allProperties) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700606 switch (p.prop) {
607 case VehicleProperty.AUDIO_FOCUS:
608 case VehicleProperty.AUDIO_VOLUME:
609 case VehicleProperty.AUDIO_VOLUME_LIMIT:
610 case VehicleProperty.AUDIO_HW_VARIANT:
611 case VehicleProperty.AUDIO_EXT_ROUTING_HINT:
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800612 case VehicleProperty.AUDIO_PARAMETERS:
Pavel Maltsevde714b72017-03-24 12:46:40 -0700613 case VehicleProperty.AUDIO_STREAM_STATE:
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700614 mProperties.put(p.prop, p);
keunyoungd32f4e62015-09-21 11:33:06 -0700615 break;
616 }
617 }
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700618 return new ArrayList<>(mProperties.values());
keunyoungd32f4e62015-09-21 11:33:06 -0700619 }
620
621 @Override
622 public void handleHalEvents(List<VehiclePropValue> values) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700623 AudioHalFocusListener focusListener;
624 AudioHalVolumeListener volumeListener;
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800625 OnParameterChangeListener parameterListener;
keunyoungd32f4e62015-09-21 11:33:06 -0700626 synchronized (this) {
Keun-young Park07182c72016-03-18 18:01:29 -0700627 focusListener = mFocusListener;
628 volumeListener = mVolumeListener;
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800629 parameterListener = mOnParameterChangeListener;
keunyoungd32f4e62015-09-21 11:33:06 -0700630 }
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800631 dispatchEventToListener(focusListener, volumeListener, parameterListener, values);
632 }
633
634 public String[] getAudioParameterKeys() {
635 VehiclePropConfig config;
636 synchronized (this) {
637 if (!isPropertySupportedLocked(AUDIO_PARAMETERS)) {
638 if (DBG) {
639 Log.i(CarLog.TAG_AUDIO, "AUDIO_PARAMETERS is not supported");
640 }
641 return null;
642 }
643 config = mProperties.get(AUDIO_PARAMETERS);
644 }
645 return config.configString.split(";");
646 }
647
648 public void setAudioParameters(String parameters) {
649 synchronized (this) {
650 if (!isPropertySupportedLocked(AUDIO_PARAMETERS)) {
651 throw new IllegalStateException("VehicleProperty.AUDIO_PARAMETERS not supported");
652 }
653 }
654 VehiclePropValue value = new VehiclePropValue();
655 value.prop = AUDIO_PARAMETERS;
656 value.value.stringValue = parameters;
657 try {
658 mVehicleHal.set(value);
659 } catch (PropertyTimeoutException e) {
660 Log.e(CarLog.TAG_AUDIO, "Cannot write to VehicleProperty.AUDIO_EXT_ROUTING_HINT", e);
661 }
662 }
663
664 public String getAudioParameters(String keys) {
665 synchronized (this) {
666 if (!isPropertySupportedLocked(AUDIO_PARAMETERS)) {
667 throw new IllegalStateException("VehicleProperty.AUDIO_PARAMETERS not supported");
668 }
669 }
670 try {
671 VehiclePropValue requested = new VehiclePropValue();
672 requested.prop = AUDIO_PARAMETERS;
673 requested.value.stringValue = keys;
674 VehiclePropValue propValue = mVehicleHal.get(requested);
675 return propValue.value.stringValue;
676 } catch (PropertyTimeoutException e) {
677 Log.e(CarLog.TAG_AUDIO, "VehicleProperty.AUDIO_PARAMETERS not ready", e);
678 return new String("");
679 }
680 }
681
682 public synchronized void setOnParameterChangeListener(OnParameterChangeListener listener) {
683 mOnParameterChangeListener = listener;
Keun-young Park07182c72016-03-18 18:01:29 -0700684 }
685
686 private void dispatchEventToListener(AudioHalFocusListener focusListener,
687 AudioHalVolumeListener volumeListener,
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800688 OnParameterChangeListener parameterListener,
Keun-young Park07182c72016-03-18 18:01:29 -0700689 List<VehiclePropValue> values) {
keunyoungd32f4e62015-09-21 11:33:06 -0700690 for (VehiclePropValue v : values) {
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700691 switch (v.prop) {
692 case VehicleProperty.AUDIO_FOCUS: {
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800693 ArrayList<Integer> vec = v.value.int32Values;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700694 int focusState = vec.get(VehicleAudioFocusIndex.FOCUS);
695 int streams = vec.get(VehicleAudioFocusIndex.STREAMS);
696 int externalFocus = vec.get(VehicleAudioFocusIndex.EXTERNAL_FOCUS_STATE);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700697 if (focusListener != null) {
698 focusListener.onFocusChange(focusState, streams, externalFocus);
699 }
700 } break;
Pavel Maltsevde714b72017-03-24 12:46:40 -0700701 case VehicleProperty.AUDIO_STREAM_STATE: {
702 ArrayList<Integer> vec = v.value.int32Values;
703 boolean streamStarted = vec.get(0) == VEHICLE_AUDIO_STREAM_STATE_STARTED;
704 int streamNum = vec.get(1);
705 if (focusListener != null) {
706 focusListener.onStreamStatusChange(streamNum, streamStarted);
707 }
708 } break;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700709 case AUDIO_VOLUME: {
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800710 ArrayList<Integer> vec = v.value.int32Values;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700711 int volume = vec.get(VehicleAudioVolumeIndex.INDEX_VOLUME);
712 int streamNum = vec.get(VehicleAudioVolumeIndex.INDEX_STREAM);
713 int volumeState = vec.get(VehicleAudioVolumeIndex.INDEX_STATE);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700714 if (volumeListener != null) {
715 volumeListener.onVolumeChange(streamNum, volume, volumeState);
716 }
keunyoung5c7cb262015-10-19 10:47:45 -0700717 } break;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700718 case AUDIO_VOLUME_LIMIT: {
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800719 ArrayList<Integer> vec = v.value.int32Values;
Pavel Maltsev0d07c762016-11-03 16:40:15 -0700720 int stream = vec.get(VehicleAudioVolumeLimitIndex.STREAM);
721 int maxVolume = vec.get(VehicleAudioVolumeLimitIndex.MAX_VOLUME);
Keun-young Park6b3f7192016-03-25 18:41:49 -0700722 if (volumeListener != null) {
723 volumeListener.onVolumeLimitChange(stream, maxVolume);
724 }
keunyoungd32f4e62015-09-21 11:33:06 -0700725 } break;
Keun-young Parkfe1a8f12017-01-17 20:06:34 -0800726 case AUDIO_PARAMETERS: {
727 String params = v.value.stringValue;
728 if (parameterListener != null) {
729 parameterListener.onParameterChange(params);
730 }
731 }
keunyoungd32f4e62015-09-21 11:33:06 -0700732 }
733 }
Keun-young Park07182c72016-03-18 18:01:29 -0700734 values.clear();
keunyoungd32f4e62015-09-21 11:33:06 -0700735 }
736
737 @Override
738 public void dump(PrintWriter writer) {
keunyoung5c7cb262015-10-19 10:47:45 -0700739 writer.println("*Audio HAL*");
740 writer.println(" audio H/W variant:" + mVariant);
keunyounga74b9ca2015-10-21 13:33:58 -0700741 writer.println(" Supported properties");
742 VehicleHal.dumpProperties(writer, mProperties.values());
keunyoungd32f4e62015-09-21 11:33:06 -0700743 }
744
745}