A2dpService.java revision 86c29fe88456bdcfbd4334647b04ef81ff384a06
1/* 2 * Copyright (C) 2012 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 */ 16 17package com.android.bluetooth.a2dp; 18 19import android.bluetooth.BluetoothCodecConfig; 20import android.bluetooth.BluetoothDevice; 21import android.bluetooth.BluetoothProfile; 22import android.bluetooth.BluetoothUuid; 23import android.bluetooth.IBluetoothA2dp; 24import android.os.ParcelUuid; 25import android.provider.Settings; 26import android.util.Log; 27import com.android.bluetooth.avrcp.Avrcp; 28import com.android.bluetooth.btservice.ProfileService; 29import com.android.bluetooth.Utils; 30import java.util.ArrayList; 31import java.util.List; 32import java.util.Objects; 33 34/** 35 * Provides Bluetooth A2DP profile, as a service in the Bluetooth application. 36 * @hide 37 */ 38public class A2dpService extends ProfileService { 39 private static final boolean DBG = false; 40 private static final String TAG="A2dpService"; 41 42 private A2dpStateMachine mStateMachine; 43 private Avrcp mAvrcp; 44 private static A2dpService sAd2dpService; 45 static final ParcelUuid[] A2DP_SOURCE_UUID = { 46 BluetoothUuid.AudioSource 47 }; 48 static final ParcelUuid[] A2DP_SOURCE_SINK_UUIDS = { 49 BluetoothUuid.AudioSource, 50 BluetoothUuid.AudioSink 51 }; 52 53 protected String getName() { 54 return TAG; 55 } 56 57 protected IProfileServiceBinder initBinder() { 58 return new BluetoothA2dpBinder(this); 59 } 60 61 protected boolean start() { 62 mAvrcp = Avrcp.make(this); 63 mStateMachine = A2dpStateMachine.make(this, this); 64 setA2dpService(this); 65 return true; 66 } 67 68 protected boolean stop() { 69 if (mStateMachine != null) { 70 mStateMachine.doQuit(); 71 } 72 if (mAvrcp != null) { 73 mAvrcp.doQuit(); 74 } 75 return true; 76 } 77 78 protected boolean cleanup() { 79 if (mStateMachine!= null) { 80 mStateMachine.cleanup(); 81 } 82 if (mAvrcp != null) { 83 mAvrcp.cleanup(); 84 mAvrcp = null; 85 } 86 clearA2dpService(); 87 return true; 88 } 89 90 //API Methods 91 92 public static synchronized A2dpService getA2dpService(){ 93 if (sAd2dpService != null && sAd2dpService.isAvailable()) { 94 if (DBG) Log.d(TAG, "getA2DPService(): returning " + sAd2dpService); 95 return sAd2dpService; 96 } 97 if (DBG) { 98 if (sAd2dpService == null) { 99 Log.d(TAG, "getA2dpService(): service is NULL"); 100 } else if (!(sAd2dpService.isAvailable())) { 101 Log.d(TAG,"getA2dpService(): service is not available"); 102 } 103 } 104 return null; 105 } 106 107 private static synchronized void setA2dpService(A2dpService instance) { 108 if (instance != null && instance.isAvailable()) { 109 if (DBG) Log.d(TAG, "setA2dpService(): set to: " + sAd2dpService); 110 sAd2dpService = instance; 111 } else { 112 if (DBG) { 113 if (sAd2dpService == null) { 114 Log.d(TAG, "setA2dpService(): service not available"); 115 } else if (!sAd2dpService.isAvailable()) { 116 Log.d(TAG,"setA2dpService(): service is cleaning up"); 117 } 118 } 119 } 120 } 121 122 private static synchronized void clearA2dpService() { 123 sAd2dpService = null; 124 } 125 126 public boolean connect(BluetoothDevice device) { 127 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 128 "Need BLUETOOTH ADMIN permission"); 129 130 if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) { 131 return false; 132 } 133 ParcelUuid[] featureUuids = device.getUuids(); 134 if ((BluetoothUuid.containsAnyUuid(featureUuids, A2DP_SOURCE_UUID)) && 135 !(BluetoothUuid.containsAllUuids(featureUuids ,A2DP_SOURCE_SINK_UUIDS))) { 136 Log.e(TAG,"Remote does not have A2dp Sink UUID"); 137 return false; 138 } 139 140 int connectionState = mStateMachine.getConnectionState(device); 141 if (connectionState == BluetoothProfile.STATE_CONNECTED || 142 connectionState == BluetoothProfile.STATE_CONNECTING) { 143 return false; 144 } 145 146 mStateMachine.sendMessage(A2dpStateMachine.CONNECT, device); 147 return true; 148 } 149 150 boolean disconnect(BluetoothDevice device) { 151 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 152 "Need BLUETOOTH ADMIN permission"); 153 int connectionState = mStateMachine.getConnectionState(device); 154 if (connectionState != BluetoothProfile.STATE_CONNECTED && 155 connectionState != BluetoothProfile.STATE_CONNECTING) { 156 return false; 157 } 158 159 mStateMachine.sendMessage(A2dpStateMachine.DISCONNECT, device); 160 return true; 161 } 162 163 public List<BluetoothDevice> getConnectedDevices() { 164 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 165 return mStateMachine.getConnectedDevices(); 166 } 167 168 List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 169 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 170 return mStateMachine.getDevicesMatchingConnectionStates(states); 171 } 172 173 public int getConnectionState(BluetoothDevice device) { 174 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 175 return mStateMachine.getConnectionState(device); 176 } 177 178 public boolean setPriority(BluetoothDevice device, int priority) { 179 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 180 "Need BLUETOOTH_ADMIN permission"); 181 Settings.Global.putInt(getContentResolver(), 182 Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()), 183 priority); 184 if (DBG) Log.d(TAG,"Saved priority " + device + " = " + priority); 185 return true; 186 } 187 188 public int getPriority(BluetoothDevice device) { 189 enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, 190 "Need BLUETOOTH_ADMIN permission"); 191 int priority = Settings.Global.getInt(getContentResolver(), 192 Settings.Global.getBluetoothA2dpSinkPriorityKey(device.getAddress()), 193 BluetoothProfile.PRIORITY_UNDEFINED); 194 return priority; 195 } 196 197 /* Absolute volume implementation */ 198 public boolean isAvrcpAbsoluteVolumeSupported() { 199 return mAvrcp.isAbsoluteVolumeSupported(); 200 } 201 202 public void adjustAvrcpAbsoluteVolume(int direction) { 203 mAvrcp.adjustVolume(direction); 204 } 205 206 public void setAvrcpAbsoluteVolume(int volume) { 207 mAvrcp.setAbsoluteVolume(volume); 208 } 209 210 public void setAvrcpAudioState(int state) { 211 mAvrcp.setA2dpAudioState(state); 212 } 213 214 public void resetAvrcpBlacklist(BluetoothDevice device) { 215 if (mAvrcp != null) { 216 mAvrcp.resetBlackList(device.getAddress()); 217 } 218 } 219 220 synchronized boolean isA2dpPlaying(BluetoothDevice device) { 221 enforceCallingOrSelfPermission(BLUETOOTH_PERM, 222 "Need BLUETOOTH permission"); 223 if (DBG) Log.d(TAG, "isA2dpPlaying(" + device + ")"); 224 return mStateMachine.isPlaying(device); 225 } 226 227 public BluetoothCodecConfig getCodecConfig() { 228 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 229 if (DBG) Log.d(TAG, "getCodecConfig()"); 230 return mStateMachine.getCodecConfig(); 231 } 232 233 public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) { 234 enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); 235 if (DBG) Log.d(TAG, "setCodecConfigPreference(): " + Objects.toString(codecConfig)); 236 mStateMachine.setCodecConfigPreference(codecConfig); 237 } 238 239 //Binder object: Must be static class or memory leak may occur 240 private static class BluetoothA2dpBinder extends IBluetoothA2dp.Stub 241 implements IProfileServiceBinder { 242 private A2dpService mService; 243 244 private A2dpService getService() { 245 if (!Utils.checkCaller()) { 246 Log.w(TAG,"A2dp call not allowed for non-active user"); 247 return null; 248 } 249 250 if (mService != null && mService.isAvailable()) { 251 return mService; 252 } 253 return null; 254 } 255 256 BluetoothA2dpBinder(A2dpService svc) { 257 mService = svc; 258 } 259 260 public boolean cleanup() { 261 mService = null; 262 return true; 263 } 264 265 public boolean connect(BluetoothDevice device) { 266 A2dpService service = getService(); 267 if (service == null) return false; 268 return service.connect(device); 269 } 270 271 public boolean disconnect(BluetoothDevice device) { 272 A2dpService service = getService(); 273 if (service == null) return false; 274 return service.disconnect(device); 275 } 276 277 public List<BluetoothDevice> getConnectedDevices() { 278 A2dpService service = getService(); 279 if (service == null) return new ArrayList<BluetoothDevice>(0); 280 return service.getConnectedDevices(); 281 } 282 283 public List<BluetoothDevice> getDevicesMatchingConnectionStates(int[] states) { 284 A2dpService service = getService(); 285 if (service == null) return new ArrayList<BluetoothDevice>(0); 286 return service.getDevicesMatchingConnectionStates(states); 287 } 288 289 public int getConnectionState(BluetoothDevice device) { 290 A2dpService service = getService(); 291 if (service == null) return BluetoothProfile.STATE_DISCONNECTED; 292 return service.getConnectionState(device); 293 } 294 295 public boolean setPriority(BluetoothDevice device, int priority) { 296 A2dpService service = getService(); 297 if (service == null) return false; 298 return service.setPriority(device, priority); 299 } 300 301 public int getPriority(BluetoothDevice device) { 302 A2dpService service = getService(); 303 if (service == null) return BluetoothProfile.PRIORITY_UNDEFINED; 304 return service.getPriority(device); 305 } 306 307 public boolean isAvrcpAbsoluteVolumeSupported() { 308 A2dpService service = getService(); 309 if (service == null) return false; 310 return service.isAvrcpAbsoluteVolumeSupported(); 311 } 312 313 public void adjustAvrcpAbsoluteVolume(int direction) { 314 A2dpService service = getService(); 315 if (service == null) return; 316 service.adjustAvrcpAbsoluteVolume(direction); 317 } 318 319 public void setAvrcpAbsoluteVolume(int volume) { 320 A2dpService service = getService(); 321 if (service == null) return; 322 service.setAvrcpAbsoluteVolume(volume); 323 } 324 325 public boolean isA2dpPlaying(BluetoothDevice device) { 326 A2dpService service = getService(); 327 if (service == null) return false; 328 return service.isA2dpPlaying(device); 329 } 330 331 public BluetoothCodecConfig getCodecConfig() { 332 A2dpService service = getService(); 333 if (service == null) return null; 334 return service.getCodecConfig(); 335 } 336 337 public void setCodecConfigPreference(BluetoothCodecConfig codecConfig) { 338 A2dpService service = getService(); 339 if (service == null) return; 340 service.setCodecConfigPreference(codecConfig); 341 } 342 }; 343 344 @Override 345 public void dump(StringBuilder sb) { 346 super.dump(sb); 347 if (mStateMachine != null) { 348 mStateMachine.dump(sb); 349 } 350 if (mAvrcp != null) { 351 mAvrcp.dump(sb); 352 } 353 } 354} 355