1 /* 2 * Copyright 2017 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 17 /* 18 * Defines the native inteface that is used by state machine/service to 19 * send or receive messages from the native stack. This file is registered 20 * for the native methods in the corresponding JNI C++ file. 21 */ 22 package com.android.bluetooth.a2dp; 23 24 import android.bluetooth.BluetoothAdapter; 25 import android.bluetooth.BluetoothCodecConfig; 26 import android.bluetooth.BluetoothCodecStatus; 27 import android.bluetooth.BluetoothDevice; 28 import android.support.annotation.VisibleForTesting; 29 import android.util.Log; 30 31 import com.android.bluetooth.Utils; 32 import com.android.internal.annotations.GuardedBy; 33 34 /** 35 * A2DP Native Interface to/from JNI. 36 */ 37 public class A2dpNativeInterface { 38 private static final String TAG = "A2dpNativeInterface"; 39 private static final boolean DBG = true; 40 private BluetoothAdapter mAdapter; 41 42 @GuardedBy("INSTANCE_LOCK") 43 private static A2dpNativeInterface sInstance; 44 private static final Object INSTANCE_LOCK = new Object(); 45 46 static { 47 classInitNative(); 48 } 49 50 @VisibleForTesting 51 private A2dpNativeInterface() { 52 mAdapter = BluetoothAdapter.getDefaultAdapter(); 53 if (mAdapter == null) { 54 Log.wtfStack(TAG, "No Bluetooth Adapter Available"); 55 } 56 } 57 58 /** 59 * Get singleton instance. 60 */ 61 public static A2dpNativeInterface getInstance() { 62 synchronized (INSTANCE_LOCK) { 63 if (sInstance == null) { 64 sInstance = new A2dpNativeInterface(); 65 } 66 return sInstance; 67 } 68 } 69 70 /** 71 * Initializes the native interface. 72 * 73 * @param maxConnectedAudioDevices maximum number of A2DP Sink devices that can be connected 74 * simultaneously 75 * @param codecConfigPriorities an array with the codec configuration 76 * priorities to configure. 77 */ 78 public void init(int maxConnectedAudioDevices, BluetoothCodecConfig[] codecConfigPriorities) { 79 initNative(maxConnectedAudioDevices, codecConfigPriorities); 80 } 81 82 /** 83 * Cleanup the native interface. 84 */ 85 public void cleanup() { 86 cleanupNative(); 87 } 88 89 /** 90 * Initiates A2DP connection to a remote device. 91 * 92 * @param device the remote device 93 * @return true on success, otherwise false. 94 */ 95 public boolean connectA2dp(BluetoothDevice device) { 96 return connectA2dpNative(getByteAddress(device)); 97 } 98 99 /** 100 * Disconnects A2DP from a remote device. 101 * 102 * @param device the remote device 103 * @return true on success, otherwise false. 104 */ 105 public boolean disconnectA2dp(BluetoothDevice device) { 106 return disconnectA2dpNative(getByteAddress(device)); 107 } 108 109 /** 110 * Sets a connected A2DP remote device as active. 111 * 112 * @param device the remote device 113 * @return true on success, otherwise false. 114 */ 115 public boolean setActiveDevice(BluetoothDevice device) { 116 return setActiveDeviceNative(getByteAddress(device)); 117 } 118 119 /** 120 * Sets the codec configuration preferences. 121 * 122 * @param device the remote Bluetooth device 123 * @param codecConfigArray an array with the codec configurations to 124 * configure. 125 * @return true on success, otherwise false. 126 */ 127 public boolean setCodecConfigPreference(BluetoothDevice device, 128 BluetoothCodecConfig[] codecConfigArray) { 129 return setCodecConfigPreferenceNative(getByteAddress(device), 130 codecConfigArray); 131 } 132 133 private BluetoothDevice getDevice(byte[] address) { 134 return mAdapter.getRemoteDevice(address); 135 } 136 137 private byte[] getByteAddress(BluetoothDevice device) { 138 if (device == null) { 139 return Utils.getBytesFromAddress("00:00:00:00:00:00"); 140 } 141 return Utils.getBytesFromAddress(device.getAddress()); 142 } 143 144 private void sendMessageToService(A2dpStackEvent event) { 145 A2dpService service = A2dpService.getA2dpService(); 146 if (service != null) { 147 service.messageFromNative(event); 148 } else { 149 Log.w(TAG, "Event ignored, service not available: " + event); 150 } 151 } 152 153 // Callbacks from the native stack back into the Java framework. 154 // All callbacks are routed via the Service which will disambiguate which 155 // state machine the message should be routed to. 156 157 private void onConnectionStateChanged(byte[] address, int state) { 158 A2dpStackEvent event = 159 new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED); 160 event.device = getDevice(address); 161 event.valueInt = state; 162 163 if (DBG) { 164 Log.d(TAG, "onConnectionStateChanged: " + event); 165 } 166 sendMessageToService(event); 167 } 168 169 private void onAudioStateChanged(byte[] address, int state) { 170 A2dpStackEvent event = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_AUDIO_STATE_CHANGED); 171 event.device = getDevice(address); 172 event.valueInt = state; 173 174 if (DBG) { 175 Log.d(TAG, "onAudioStateChanged: " + event); 176 } 177 sendMessageToService(event); 178 } 179 180 private void onCodecConfigChanged(byte[] address, 181 BluetoothCodecConfig newCodecConfig, 182 BluetoothCodecConfig[] codecsLocalCapabilities, 183 BluetoothCodecConfig[] codecsSelectableCapabilities) { 184 A2dpStackEvent event = new A2dpStackEvent(A2dpStackEvent.EVENT_TYPE_CODEC_CONFIG_CHANGED); 185 event.device = getDevice(address); 186 event.codecStatus = new BluetoothCodecStatus(newCodecConfig, 187 codecsLocalCapabilities, 188 codecsSelectableCapabilities); 189 if (DBG) { 190 Log.d(TAG, "onCodecConfigChanged: " + event); 191 } 192 sendMessageToService(event); 193 } 194 195 // Native methods that call into the JNI interface 196 private static native void classInitNative(); 197 private native void initNative(int maxConnectedAudioDevices, 198 BluetoothCodecConfig[] codecConfigPriorities); 199 private native void cleanupNative(); 200 private native boolean connectA2dpNative(byte[] address); 201 private native boolean disconnectA2dpNative(byte[] address); 202 private native boolean setActiveDeviceNative(byte[] address); 203 private native boolean setCodecConfigPreferenceNative(byte[] address, 204 BluetoothCodecConfig[] codecConfigArray); 205 } 206