blob: 2ea45d567f6add5cb7d037756ebf8dc4d31d00eb [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2008 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 android.bluetooth;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.server.BluetoothA2dpService;
22import android.content.Context;
23import android.os.ServiceManager;
24import android.os.RemoteException;
25import android.os.IBinder;
26import android.util.Log;
27
28import java.util.List;
29
30/**
31 * Public API for controlling the Bluetooth A2DP Profile Service.
32 *
33 * BluetoothA2dp is a proxy object for controlling the Bluetooth A2DP
34 * Service via IPC.
35 *
36 * Creating a BluetoothA2dp object will initiate a binding with the
37 * BluetoothHeadset service. Users of this object should call close() when they
38 * are finished, so that this proxy object can unbind from the service.
39 *
40 * Currently the BluetoothA2dp service runs in the system server and this
41 * proxy object will be immediately bound to the service on construction.
42 * However this may change in future releases, and error codes such as
43 * BluetoothError.ERROR_IPC_NOT_READY will be returned from this API when the
44 * proxy object is not yet attached.
45 *
46 * Currently this class provides methods to connect to A2DP audio sinks.
47 *
48 * @hide
49 */
50public class BluetoothA2dp {
51 private static final String TAG = "BluetoothA2dp";
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -080052 private static final boolean DBG = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080053
54 /** int extra for SINK_STATE_CHANGED_ACTION */
55 public static final String SINK_STATE =
56 "android.bluetooth.a2dp.intent.SINK_STATE";
57 /** int extra for SINK_STATE_CHANGED_ACTION */
58 public static final String SINK_PREVIOUS_STATE =
59 "android.bluetooth.a2dp.intent.SINK_PREVIOUS_STATE";
60
61 /** Indicates the state of an A2DP audio sink has changed.
62 * This intent will always contain SINK_STATE, SINK_PREVIOUS_STATE and
63 * BluetoothIntent.ADDRESS extras.
64 */
65 @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
66 public static final String SINK_STATE_CHANGED_ACTION =
67 "android.bluetooth.a2dp.intent.action.SINK_STATE_CHANGED";
68
69 public static final int STATE_DISCONNECTED = 0;
70 public static final int STATE_CONNECTING = 1;
71 public static final int STATE_CONNECTED = 2;
72 public static final int STATE_DISCONNECTING = 3;
73 /** Playing implies connected */
74 public static final int STATE_PLAYING = 4;
75
76 /** Default priority for a2dp devices that should allow incoming
77 * connections */
78 public static final int PRIORITY_AUTO = 100;
79 /** Default priority for a2dp devices that should not allow incoming
80 * connections */
81 public static final int PRIORITY_OFF = 0;
82 private final IBluetoothA2dp mService;
83 private final Context mContext;
84
85 /**
86 * Create a BluetoothA2dp proxy object for interacting with the local
87 * Bluetooth A2DP service.
88 * @param c Context
89 */
90 public BluetoothA2dp(Context c) {
91 mContext = c;
92 IBinder b = ServiceManager.getService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE);
93 if (b == null) {
94 throw new RuntimeException("Bluetooth A2DP service not available!");
95 }
96 mService = IBluetoothA2dp.Stub.asInterface(b);
97 }
98
99 /** Initiate a connection to an A2DP sink.
100 * Listen for SINK_STATE_CHANGED_ACTION to find out when the
101 * connection is completed.
102 * @param address Remote BT address.
103 * @return Result code, negative indicates an immediate error.
104 * @hide
105 */
106 public int connectSink(String address) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800107 if (DBG) log("connectSink(" + address + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108 try {
109 return mService.connectSink(address);
110 } catch (RemoteException e) {
111 Log.w(TAG, "", e);
112 return BluetoothError.ERROR_IPC;
113 }
114 }
115
116 /** Initiate disconnect from an A2DP sink.
117 * Listen for SINK_STATE_CHANGED_ACTION to find out when
118 * disconnect is completed.
119 * @param address Remote BT address.
120 * @return Result code, negative indicates an immediate error.
121 * @hide
122 */
123 public int disconnectSink(String address) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800124 if (DBG) log("disconnectSink(" + address + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 try {
126 return mService.disconnectSink(address);
127 } catch (RemoteException e) {
128 Log.w(TAG, "", e);
129 return BluetoothError.ERROR_IPC;
130 }
131 }
132
133 /** Check if a specified A2DP sink is connected.
134 * @param address Remote BT address.
135 * @return True if connected (or playing), false otherwise and on error.
136 * @hide
137 */
138 public boolean isSinkConnected(String address) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800139 if (DBG) log("isSinkConnected(" + address + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 int state = getSinkState(address);
141 return state == STATE_CONNECTED || state == STATE_PLAYING;
142 }
143
144 /** Check if any A2DP sink is connected.
145 * @return a List of connected A2DP sinks, or null on error.
146 * @hide
147 */
148 public List<String> listConnectedSinks() {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800149 if (DBG) log("listConnectedSinks()");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 try {
151 return mService.listConnectedSinks();
152 } catch (RemoteException e) {
153 Log.w(TAG, "", e);
154 return null;
155 }
156 }
157
158 /** Get the state of an A2DP sink
159 * @param address Remote BT address.
160 * @return State code, or negative on error
161 * @hide
162 */
163 public int getSinkState(String address) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800164 if (DBG) log("getSinkState(" + address + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 try {
166 return mService.getSinkState(address);
167 } catch (RemoteException e) {
168 Log.w(TAG, "", e);
169 return BluetoothError.ERROR_IPC;
170 }
171 }
172
173 /**
174 * Set priority of a2dp sink.
175 * Priority is a non-negative integer. By default paired sinks will have
176 * a priority of PRIORITY_AUTO, and unpaired headset PRIORITY_NONE (0).
177 * Sinks with priority greater than zero will accept incoming connections
178 * (if no sink is currently connected).
179 * Priority for unpaired sink must be PRIORITY_NONE.
180 * @param address Paired sink
181 * @param priority Integer priority, for example PRIORITY_AUTO or
182 * PRIORITY_NONE
183 * @return Result code, negative indicates an error
184 */
185 public int setSinkPriority(String address, int priority) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800186 if (DBG) log("setSinkPriority(" + address + ", " + priority + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800187 try {
188 return mService.setSinkPriority(address, priority);
189 } catch (RemoteException e) {
190 Log.w(TAG, "", e);
191 return BluetoothError.ERROR_IPC;
192 }
193 }
194
195 /**
196 * Get priority of a2dp sink.
197 * @param address Sink
198 * @return non-negative priority, or negative error code on error.
199 */
200 public int getSinkPriority(String address) {
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800201 if (DBG) log("getSinkPriority(" + address + ")");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202 try {
203 return mService.getSinkPriority(address);
204 } catch (RemoteException e) {
205 Log.w(TAG, "", e);
206 return BluetoothError.ERROR_IPC;
207 }
208 }
209
210 /**
211 * Check class bits for possible A2DP Sink support.
212 * This is a simple heuristic that tries to guess if a device with the
213 * given class bits might be a A2DP Sink. It is not accurate for all
214 * devices. It tries to err on the side of false positives.
215 * @return True if this device might be a A2DP sink
216 */
217 public static boolean doesClassMatchSink(int btClass) {
218 if (BluetoothClass.Service.hasService(btClass, BluetoothClass.Service.RENDER)) {
219 return true;
220 }
221 // By the A2DP spec, sinks must indicate the RENDER service.
222 // However we found some that do not (Chordette). So lets also
223 // match on some other class bits.
224 switch (BluetoothClass.Device.getDevice(btClass)) {
225 case BluetoothClass.Device.AUDIO_VIDEO_HIFI_AUDIO:
226 case BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES:
227 case BluetoothClass.Device.AUDIO_VIDEO_LOUDSPEAKER:
228 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
229 return true;
230 default:
231 return false;
232 }
233 }
234
235 /** Helper for converting a state to a string.
236 * For debug use only - strings are not internationalized.
237 * @hide
238 */
239 public static String stateToString(int state) {
240 switch (state) {
241 case STATE_DISCONNECTED:
242 return "disconnected";
243 case STATE_CONNECTING:
244 return "connecting";
245 case STATE_CONNECTED:
246 return "connected";
247 case STATE_DISCONNECTING:
248 return "disconnecting";
249 case STATE_PLAYING:
250 return "playing";
251 default:
252 return "<unknown state " + state + ">";
253 }
254 }
The Android Open Source Projectf5b4b982009-03-05 20:00:43 -0800255
256 private static void log(String msg) {
257 Log.d(TAG, msg);
258 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259}