1 /* 2 * Copyright 2020 HIMSA II K/S - www.himsa.com. 3 * Represented by EHIMA - www.ehima.com 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18 package com.android.bluetooth.le_audio; 19 20 import android.bluetooth.BluetoothDevice; 21 import android.bluetooth.BluetoothLeAudioCodecConfig; 22 import android.bluetooth.BluetoothLeBroadcastMetadata; 23 24 import java.util.List; 25 /** 26 * Stack event sent via a callback from JNI to Java, or generated 27 * internally by the LeAudio State Machine. 28 */ 29 public class LeAudioStackEvent { 30 // Event types for STACK_EVENT message (coming from native in bt_le_audio.h) 31 private static final int EVENT_TYPE_NONE = 0; 32 public static final int EVENT_TYPE_CONNECTION_STATE_CHANGED = 1; 33 public static final int EVENT_TYPE_GROUP_STATUS_CHANGED = 2; 34 public static final int EVENT_TYPE_GROUP_NODE_STATUS_CHANGED = 3; 35 public static final int EVENT_TYPE_AUDIO_CONF_CHANGED = 4; 36 public static final int EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE = 5; 37 public static final int EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED = 6; 38 public static final int EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED = 7; 39 public static final int EVENT_TYPE_NATIVE_INITIALIZED = 8; 40 // -------- DO NOT PUT ANY NEW UNICAST EVENTS BELOW THIS LINE------------- 41 public static final int EVENT_TYPE_UNICAST_MAX = 9; 42 43 // Broadcast related events 44 public static final int EVENT_TYPE_BROADCAST_CREATED = EVENT_TYPE_UNICAST_MAX + 1; 45 public static final int EVENT_TYPE_BROADCAST_DESTROYED = EVENT_TYPE_UNICAST_MAX + 2; 46 public static final int EVENT_TYPE_BROADCAST_STATE = EVENT_TYPE_UNICAST_MAX + 3; 47 public static final int EVENT_TYPE_BROADCAST_METADATA_CHANGED = EVENT_TYPE_UNICAST_MAX + 4; 48 49 // Do not modify without updating the HAL bt_le_audio.h files. 50 // Match up with GroupStatus enum of bt_le_audio.h 51 static final int CONNECTION_STATE_DISCONNECTED = 0; 52 static final int CONNECTION_STATE_CONNECTING = 1; 53 static final int CONNECTION_STATE_CONNECTED = 2; 54 static final int CONNECTION_STATE_DISCONNECTING = 3; 55 56 static final int GROUP_STATUS_INACTIVE = 0; 57 static final int GROUP_STATUS_ACTIVE = 1; 58 static final int GROUP_STATUS_TURNED_IDLE_DURING_CALL = 2; 59 60 static final int GROUP_NODE_ADDED = 1; 61 static final int GROUP_NODE_REMOVED = 2; 62 63 // Do not modify without updating the HAL bt_le_audio.h files. 64 // Match up with BroadcastState enum of bt_le_audio.h 65 static final int BROADCAST_STATE_STOPPED = 0; 66 static final int BROADCAST_STATE_CONFIGURING = 1; 67 static final int BROADCAST_STATE_PAUSED = 2; 68 static final int BROADCAST_STATE_STOPPING = 3; 69 static final int BROADCAST_STATE_STREAMING = 4; 70 71 public int type = EVENT_TYPE_NONE; 72 public BluetoothDevice device; 73 public int valueInt1 = 0; 74 public int valueInt2 = 0; 75 public int valueInt3 = 0; 76 public int valueInt4 = 0; 77 public int valueInt5 = 0; 78 public boolean valueBool1 = false; 79 public BluetoothLeAudioCodecConfig valueCodec1; 80 public BluetoothLeAudioCodecConfig valueCodec2; 81 public List<BluetoothLeAudioCodecConfig> valueCodecList1; 82 public List<BluetoothLeAudioCodecConfig> valueCodecList2; 83 public BluetoothLeBroadcastMetadata broadcastMetadata; 84 LeAudioStackEvent(int type)85 LeAudioStackEvent(int type) { 86 this.type = type; 87 } 88 89 @Override toString()90 public String toString() { 91 // event dump 92 StringBuilder result = new StringBuilder(); 93 result.append("LeAudioStackEvent {type:" + eventTypeToString(type)); 94 result.append(", device:" + device); 95 result.append(", value1:" + eventTypeValue1ToString(type, valueInt1)); 96 result.append(", value2:" + eventTypeValue2ToString(type, valueInt2)); 97 result.append(", value3:" + eventTypeValue3ToString(type, valueInt3)); 98 result.append(", value4:" + eventTypeValue4ToString(type, valueInt4)); 99 result.append(", value5:" + eventTypeValue5ToString(type, valueInt5)); 100 result.append(", valueBool1:" + eventTypeValueBool1ToString(type, valueBool1)); 101 result.append(", valueCodec1:" + eventTypeValueCodec1ToString(type, valueCodec1)); 102 result.append(", valueCodec2:" + eventTypeValueCodec2ToString(type, valueCodec2)); 103 result.append(", valueCodecList1:" 104 + eventTypeValueCodecList1ToString(type, valueCodecList1)); 105 result.append(", valueCodecList2:" 106 + eventTypeValueCodecList2ToString(type, valueCodecList2)); 107 if (type == EVENT_TYPE_BROADCAST_METADATA_CHANGED) { 108 result.append(", broadcastMetadata:" 109 + eventTypeValueBroadcastMetadataToString(broadcastMetadata)); 110 } 111 result.append("}"); 112 return result.toString(); 113 } 114 eventTypeToString(int type)115 private static String eventTypeToString(int type) { 116 switch (type) { 117 case EVENT_TYPE_NONE: 118 return "EVENT_TYPE_NONE"; 119 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 120 return "EVENT_TYPE_CONNECTION_STATE_CHANGED"; 121 case EVENT_TYPE_GROUP_STATUS_CHANGED: 122 return "EVENT_TYPE_GROUP_STATUS_CHANGED"; 123 case EVENT_TYPE_GROUP_NODE_STATUS_CHANGED: 124 return "EVENT_TYPE_GROUP_NODE_STATUS_CHANGED"; 125 case EVENT_TYPE_AUDIO_CONF_CHANGED: 126 return "EVENT_TYPE_AUDIO_CONF_CHANGED"; 127 case EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE: 128 return "EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE"; 129 case EVENT_TYPE_BROADCAST_CREATED: 130 return "EVENT_TYPE_BROADCAST_CREATED"; 131 case EVENT_TYPE_BROADCAST_DESTROYED: 132 return "EVENT_TYPE_BROADCAST_DESTROYED"; 133 case EVENT_TYPE_BROADCAST_STATE: 134 return "EVENT_TYPE_BROADCAST_STATE"; 135 case EVENT_TYPE_BROADCAST_METADATA_CHANGED: 136 return "EVENT_TYPE_BROADCAST_METADATA_CHANGED"; 137 case EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED: 138 return "EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED"; 139 case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED: 140 return "EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED"; 141 case EVENT_TYPE_NATIVE_INITIALIZED: 142 return "EVENT_TYPE_NATIVE_INITIALIZED"; 143 default: 144 return "EVENT_TYPE_UNKNOWN:" + type; 145 } 146 } 147 eventTypeValue1ToString(int type, int value)148 private static String eventTypeValue1ToString(int type, int value) { 149 switch (type) { 150 case EVENT_TYPE_CONNECTION_STATE_CHANGED: 151 switch (value) { 152 case CONNECTION_STATE_DISCONNECTED: 153 return "CONNECTION_STATE_DISCONNECTED"; 154 case CONNECTION_STATE_CONNECTING: 155 return "CONNECTION_STATE_CONNECTING"; 156 case CONNECTION_STATE_CONNECTED: 157 return "CONNECTION_STATE_CONNECTED"; 158 case CONNECTION_STATE_DISCONNECTING: 159 return "CONNECTION_STATE_DISCONNECTING"; 160 default: 161 return "UNKNOWN"; 162 } 163 case EVENT_TYPE_GROUP_NODE_STATUS_CHANGED: 164 // same as EVENT_TYPE_GROUP_STATUS_CHANGED 165 case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED: 166 // same as EVENT_TYPE_GROUP_STATUS_CHANGED 167 case EVENT_TYPE_GROUP_STATUS_CHANGED: 168 return "{group_id:" + Integer.toString(value) + "}"; 169 case EVENT_TYPE_AUDIO_CONF_CHANGED: 170 // FIXME: It should have proper direction names here 171 return "{direction:" + value + "}"; 172 case EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE: 173 return "{sink_audio_location:" + value + "}"; 174 case EVENT_TYPE_BROADCAST_CREATED: 175 // same as EVENT_TYPE_BROADCAST_STATE 176 case EVENT_TYPE_BROADCAST_DESTROYED: 177 // same as EVENT_TYPE_BROADCAST_STATE 178 case EVENT_TYPE_BROADCAST_METADATA_CHANGED: 179 // same as EVENT_TYPE_BROADCAST_STATE 180 case EVENT_TYPE_BROADCAST_STATE: 181 return "{broadcastId:" + value + "}"; 182 default: 183 break; 184 } 185 return Integer.toString(value); 186 } 187 eventTypeValue2ToString(int type, int value)188 private static String eventTypeValue2ToString(int type, int value) { 189 switch (type) { 190 case EVENT_TYPE_GROUP_STATUS_CHANGED: 191 switch (value) { 192 case GROUP_STATUS_ACTIVE: 193 return "GROUP_STATUS_ACTIVE"; 194 case GROUP_STATUS_INACTIVE: 195 return "GROUP_STATUS_INACTIVE"; 196 case GROUP_STATUS_TURNED_IDLE_DURING_CALL: 197 return "GROUP_STATUS_TURNED_IDLE_DURING_CALL"; 198 default: 199 break; 200 } 201 break; 202 case EVENT_TYPE_GROUP_NODE_STATUS_CHANGED: 203 switch (value) { 204 case GROUP_NODE_ADDED: 205 return "GROUP_NODE_ADDED"; 206 case GROUP_NODE_REMOVED: 207 return "GROUP_NODE_REMOVED"; 208 default: 209 return "UNKNOWN"; 210 } 211 case EVENT_TYPE_AUDIO_CONF_CHANGED: 212 return "{group_id:" + Integer.toString(value) + "}"; 213 case EVENT_TYPE_BROADCAST_STATE: 214 return "{state:" + broadcastStateToString(value) + "}"; 215 default: 216 break; 217 } 218 return Integer.toString(value); 219 } 220 eventTypeValue3ToString(int type, int value)221 private static String eventTypeValue3ToString(int type, int value) { 222 switch (type) { 223 case EVENT_TYPE_AUDIO_CONF_CHANGED: 224 // FIXME: It should have proper location names here 225 return "{snk_audio_loc:" + value + "}"; 226 default: 227 break; 228 } 229 return Integer.toString(value); 230 } 231 eventTypeValue4ToString(int type, int value)232 private static String eventTypeValue4ToString(int type, int value) { 233 switch (type) { 234 case EVENT_TYPE_AUDIO_CONF_CHANGED: 235 // FIXME: It should have proper location names here 236 return "{src_audio_loc:" + value + "}"; 237 default: 238 break; 239 } 240 return Integer.toString(value); 241 } 242 eventTypeValue5ToString(int type, int value)243 private static String eventTypeValue5ToString(int type, int value) { 244 switch (type) { 245 case EVENT_TYPE_AUDIO_CONF_CHANGED: 246 return "{available_contexts:" + Integer.toBinaryString(value) + "}"; 247 default: 248 break; 249 } 250 return Integer.toString(value); 251 } 252 eventTypeValueBool1ToString(int type, boolean value)253 private static String eventTypeValueBool1ToString(int type, boolean value) { 254 switch (type) { 255 case EVENT_TYPE_BROADCAST_CREATED: 256 return "{success:" + value + "}"; 257 default: 258 return "<unused>"; 259 } 260 } 261 eventTypeValueCodec1ToString(int type, BluetoothLeAudioCodecConfig value)262 private static String eventTypeValueCodec1ToString(int type, 263 BluetoothLeAudioCodecConfig value) { 264 switch (type) { 265 case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED: 266 return "{input codec = " + value + "}"; 267 default: 268 return "<unused>"; 269 } 270 } 271 eventTypeValueCodec2ToString(int type, BluetoothLeAudioCodecConfig value)272 private static String eventTypeValueCodec2ToString(int type, 273 BluetoothLeAudioCodecConfig value) { 274 switch (type) { 275 case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED: 276 return "{output codec = " + value + "}"; 277 default: 278 return "<unused>"; 279 } 280 } 281 eventTypeValueCodecList1ToString(int type, List<BluetoothLeAudioCodecConfig> value)282 private static String eventTypeValueCodecList1ToString(int type, 283 List<BluetoothLeAudioCodecConfig> value) { 284 switch (type) { 285 case EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED: 286 return "{input local capa codec = " + value + "}"; 287 case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED: 288 return "{input selectable codec = " + value + "}"; 289 default: 290 return "<unused>"; 291 } 292 } 293 eventTypeValueCodecList2ToString(int type, List<BluetoothLeAudioCodecConfig> value)294 private static String eventTypeValueCodecList2ToString(int type, 295 List<BluetoothLeAudioCodecConfig> value) { 296 switch (type) { 297 case EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED: 298 return "{output local capa codec = " + value + "}"; 299 case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED: 300 return "{output selectable codec = " + value + "}"; 301 default: 302 return "<unused>"; 303 } 304 } 305 broadcastStateToString(int state)306 private static String broadcastStateToString(int state) { 307 switch (state) { 308 case BROADCAST_STATE_STOPPED: 309 return "BROADCAST_STATE_STOPPED"; 310 case BROADCAST_STATE_CONFIGURING: 311 return "BROADCAST_STATE_CONFIGURING"; 312 case BROADCAST_STATE_PAUSED: 313 return "BROADCAST_STATE_PAUSED"; 314 case BROADCAST_STATE_STOPPING: 315 return "BROADCAST_STATE_STOPPING"; 316 case BROADCAST_STATE_STREAMING: 317 return "BROADCAST_STATE_STREAMING"; 318 default: 319 return "UNKNOWN"; 320 } 321 } 322 eventTypeValueBroadcastMetadataToString( BluetoothLeBroadcastMetadata meta)323 private static String eventTypeValueBroadcastMetadataToString( 324 BluetoothLeBroadcastMetadata meta) { 325 return meta.toString(); 326 } 327 encodeHexString(byte[] pduData)328 protected static String encodeHexString(byte[] pduData) { 329 StringBuilder out = new StringBuilder(pduData.length * 2); 330 for (int i = 0; i < pduData.length; i++) { 331 // MS-nibble first 332 out.append(Integer.toString((pduData[i] >> 4) & 0x0f, 16)); 333 out.append(Integer.toString(pduData[i] & 0x0f, 16)); 334 } 335 return out.toString(); 336 } 337 } 338