Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 357e7adb authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Snap for 8626810 from 13fbfc05 to tm-qpr1-release

Change-Id: I9de8781cf508c06950145bb263d1836f35d17036
parents 6f6c4045 13fbfc05
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ using bluetooth::le_audio::LeAudioClientCallbacks;
using bluetooth::le_audio::LeAudioClientInterface;

namespace android {
static jmethodID method_onInitialized;
static jmethodID method_onConnectionStateChanged;
static jmethodID method_onGroupStatus;
static jmethodID method_onGroupNodeStatus;
@@ -125,6 +126,14 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks {
 public:
  ~LeAudioClientCallbacksImpl() = default;

  void OnInitialized(void) override {
    LOG(INFO) << __func__;
    std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
    CallbackEnv sCallbackEnv(__func__);
    if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;
    sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onInitialized);
  }

  void OnConnectionState(ConnectionState state,
                         const RawAddress& bd_addr) override {
    LOG(INFO) << __func__ << ", state:" << int(state);
@@ -280,6 +289,7 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  method_onAudioConf = env->GetMethodID(clazz, "onAudioConf", "(IIIII)V");
  method_onSinkAudioLocationAvailable =
      env->GetMethodID(clazz, "onSinkAudioLocationAvailable", "([BI)V");
  method_onInitialized = env->GetMethodID(clazz, "onInitialized", "()V");
  method_onConnectionStateChanged =
      env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
  method_onAudioLocalCodecCapabilities =
@@ -512,6 +522,17 @@ static void setCodecConfigPreferenceNative(JNIEnv* env, jobject object,
      group_id, input_codec_config, output_codec_config);
}

static void setCcidInformationNative(JNIEnv* env, jobject object, jint ccid,
                                     jint contextType) {
  std::shared_lock<std::shared_timed_mutex> lock(interface_mutex);
  if (!sLeAudioClientInterface) {
    LOG(ERROR) << __func__ << ": Failed to get the Bluetooth LeAudio Interface";
    return;
  }

  sLeAudioClientInterface->SetCcidInformation(ccid, contextType);
}

static JNINativeMethod sMethods[] = {
    {"classInitNative", "()V", (void*)classInitNative},
    {"initNative", "([Landroid/bluetooth/BluetoothLeAudioCodecConfig;)V",
@@ -526,6 +547,7 @@ static JNINativeMethod sMethods[] = {
     "(ILandroid/bluetooth/BluetoothLeAudioCodecConfig;Landroid/bluetooth/"
     "BluetoothLeAudioCodecConfig;)V",
     (void*)setCodecConfigPreferenceNative},
    {"setCcidInformationNative", "(II)V", (void*)setCcidInformationNative},
};

/* Le Audio Broadcaster */
+49 −2
Original line number Diff line number Diff line
@@ -17,6 +17,15 @@

package com.android.bluetooth.le_audio;

import android.bluetooth.BluetoothLeAudio;
import android.os.ParcelUuid;
import android.util.Pair;

import com.android.bluetooth.btservice.ServiceFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;

@@ -30,8 +39,19 @@ public class ContentControlIdKeeper {
    public static final int CCID_MAX = 0xFF;

    private static SortedSet<Integer> sAssignedCcidList = new TreeSet();
    private static HashMap<ParcelUuid, Pair<Integer, Integer>> sUserMap = new HashMap();
    private static ServiceFactory sServiceFactory = null;

    public static synchronized int acquireCcid() {
    /**
     * Functions is used to acquire Content Control ID (Ccid). Ccid is connected
     * with a context type  and the user uuid. In most of cases user uuid is the GATT service
     * UUID which makes use of Ccid
     *
     * @param userUuid user identifier (GATT service)
     * @param contextType the context types as defined in {@link BluetoothLeAudio}
     * @return ccid to be used in the Gatt service Ccid characteristic.
    */
    public static synchronized int acquireCcid(ParcelUuid userUuid, int contextType) {
        int ccid = CCID_INVALID;

        if (sAssignedCcidList.size() == 0) {
@@ -51,11 +71,38 @@ public class ContentControlIdKeeper {
            }
        }

        if (ccid != CCID_INVALID) sAssignedCcidList.add(ccid);
        if (ccid != CCID_INVALID)  {
            sAssignedCcidList.add(ccid);
            sUserMap.put(userUuid, new Pair(ccid, contextType));

            if (sServiceFactory == null) {
                sServiceFactory = new ServiceFactory();
            }
            /* Notify LeAudioService about new ccid  */
            LeAudioService service = sServiceFactory.getLeAudioService();
            if (service != null) {
                service.setCcidInformation(userUuid, ccid, contextType);
            }
        }
        return ccid;
    }

    /**
     * Release the acquired Ccid
     *
     * @param value Ccid value to release
     */
    public static synchronized void releaseCcid(int value) {
        sAssignedCcidList.remove(value);
        sUserMap.entrySet().removeIf(entry -> entry.getValue().first.equals(value));
    }

    /**
     * Get Ccid information.
     *
     * @return Map of acquired ccids along with the user information.
     */
    public static synchronized Map<ParcelUuid, Pair<Integer, Integer>> getUserCcidMap() {
        return Collections.unmodifiableMap(sUserMap);
    }
}
+23 −0
Original line number Diff line number Diff line
@@ -90,6 +90,16 @@ public class LeAudioNativeInterface {
    // Callbacks from the native stack back into the Java framework.
    // All callbacks are routed via the Service which will disambiguate which
    // state machine the message should be routed to.
    private void onInitialized() {
        LeAudioStackEvent event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_NATIVE_INITIALIZED);

        if (DBG) {
            Log.d(TAG, "onInitialized: " + event);
        }
        sendMessageToService(event);
    }

    private void onConnectionStateChanged(int state, byte[] address) {
        LeAudioStackEvent event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_CONNECTION_STATE_CHANGED);
@@ -265,6 +275,18 @@ public class LeAudioNativeInterface {
        setCodecConfigPreferenceNative(groupId, inputCodecConfig, outputCodecConfig);
    }

    /**
     * Set content control id (Ccid) along with context type.
     * @param ccid content control id
     * @param contextType assigned contextType
     */
    public void setCcidInformation(int ccid, int contextType) {
        if (DBG) {
            Log.d(TAG, "setCcidInformation ccid: " + ccid + " context type: " + contextType);
        }
        setCcidInformationNative(ccid, contextType);
    }

    // Native methods that call into the JNI interface
    private static native void classInitNative();
    private native void initNative(BluetoothLeAudioCodecConfig[] codecConfigOffloading);
@@ -277,4 +299,5 @@ public class LeAudioNativeInterface {
    private native void setCodecConfigPreferenceNative(int groupId,
            BluetoothLeAudioCodecConfig inputCodecConfig,
            BluetoothLeAudioCodecConfig outputCodecConfig);
    private native void setCcidInformationNative(int ccid, int contextType);
}
+69 −0
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.sysprop.BluetoothProperties;
import android.util.Log;
import android.util.Pair;

import com.android.bluetooth.Utils;
import com.android.bluetooth.btservice.AdapterService;
@@ -59,6 +60,7 @@ import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ServiceFactory;
import com.android.bluetooth.btservice.storage.DatabaseManager;
import com.android.bluetooth.mcp.McpService;
import com.android.bluetooth.tbs.TbsGatt;
import com.android.bluetooth.vc.VolumeControlService;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -119,6 +121,7 @@ public class LeAudioService extends ProfileService {
    ServiceFactory mServiceFactory = new ServiceFactory();

    LeAudioNativeInterface mLeAudioNativeInterface;
    boolean mLeAudioNativeIsInitialized = false;
    LeAudioBroadcasterNativeInterface mLeAudioBroadcasterNativeInterface = null;
    @VisibleForTesting
    AudioManager mAudioManager;
@@ -328,6 +331,7 @@ public class LeAudioService extends ProfileService {
        // Cleanup native interfaces
        mLeAudioNativeInterface.cleanup();
        mLeAudioNativeInterface = null;
        mLeAudioNativeIsInitialized = false;

        // Set the service and BLE devices as inactive
        setLeAudioService(null);
@@ -553,6 +557,10 @@ public class LeAudioService extends ProfileService {
     * @return true on success, otherwise false
     */
    boolean groupAddNode(int groupId, BluetoothDevice device) {
        if (!mLeAudioNativeIsInitialized) {
            Log.e(TAG, "Le Audio not initialized properly.");
            return false;
        }
        return mLeAudioNativeInterface.groupAddNode(groupId, device);
    }

@@ -563,6 +571,10 @@ public class LeAudioService extends ProfileService {
     * @return true on success, otherwise false
     */
    boolean groupRemoveNode(int groupId, BluetoothDevice device) {
        if (!mLeAudioNativeIsInitialized) {
            Log.e(TAG, "Le Audio not initialized properly.");
            return false;
        }
        return mLeAudioNativeInterface.groupRemoveNode(groupId, device);
    }

@@ -952,6 +964,10 @@ public class LeAudioService extends ProfileService {
            return;
        }

        if (!mLeAudioNativeIsInitialized) {
            Log.e(TAG, "Le Audio not initialized properly.");
            return;
        }
        mLeAudioNativeInterface.groupSetActive(groupId);
    }

@@ -1346,6 +1362,14 @@ public class LeAudioService extends ProfileService {
                mBroadcastMetadataList.put(broadcastId, stackEvent.broadcastMetadata);
                notifyBroadcastMetadataChanged(broadcastId, stackEvent.broadcastMetadata);
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_NATIVE_INITIALIZED) {
            mLeAudioNativeIsInitialized = true;
            for (Map.Entry<ParcelUuid, Pair<Integer, Integer>> entry :
                    ContentControlIdKeeper.getUserCcidMap().entrySet()) {
                ParcelUuid userUuid = entry.getKey();
                Pair<Integer, Integer> ccidInformation = entry.getValue();
                setCcidInformation(userUuid, ccidInformation.first, ccidInformation.second);
            }
        }

        if (intent != null) {
@@ -1694,6 +1718,25 @@ public class LeAudioService extends ProfileService {
        }
    }

    /**
     * Set the user application ccid along with used context type
     * @param userUuid user uuid
     * @param ccid content control id
     * @param contextType context type
     */
    public void setCcidInformation(ParcelUuid userUuid, int ccid, int contextType) {
        /* for the moment we care only for GMCS and GTBS */
        if (userUuid != BluetoothUuid.GENERIC_MEDIA_CONTROL
                && userUuid.getUuid() != TbsGatt.UUID_GTBS) {
            return;
        }
        if (!mLeAudioNativeIsInitialized) {
            Log.e(TAG, "Le Audio not initialized properly.");
            return;
        }
        mLeAudioNativeInterface.setCcidInformation(ccid, contextType);
    }

    /**
     * Set volume for streaming devices
     * @param volume volume to set
@@ -1987,6 +2030,11 @@ public class LeAudioService extends ProfileService {
            return;
        }

        if (!mLeAudioNativeIsInitialized) {
            Log.e(TAG, "Le Audio not initialized properly.");
            return;
        }

        mLeAudioNativeInterface.setCodecConfigPreference(groupId,
                                inputCodecConfig, outputCodecConfig);
    }
@@ -2224,6 +2272,27 @@ public class LeAudioService extends ProfileService {
            }
        }

        @Override
        public void setCcidInformation(ParcelUuid userUuid, int ccid, int contextType,
                AttributionSource source,
                SynchronousResultReceiver receiver) {
            try {
                Objects.requireNonNull(userUuid, "userUuid cannot be null");
                Objects.requireNonNull(source, "source cannot be null");
                Objects.requireNonNull(receiver, "receiver cannot be null");

                LeAudioService service = getService(source);
                if (service == null) {
                    throw new IllegalStateException("service is null");
                }
                enforceBluetoothPrivilegedPermission(service);
                service.setCcidInformation(userUuid, ccid, contextType);
                receiver.send(null);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }

        @Override
        public void getGroupId(BluetoothDevice device, AttributionSource source,
                SynchronousResultReceiver receiver) {
+4 −1
Original line number Diff line number Diff line
@@ -36,8 +36,9 @@ public class LeAudioStackEvent {
    public static final int EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE = 5;
    public static final int EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED = 6;
    public static final int EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED = 7;
    public static final int EVENT_TYPE_NATIVE_INITIALIZED = 8;
        // -------- DO NOT PUT ANY NEW UNICAST EVENTS BELOW THIS LINE-------------
    public static final int EVENT_TYPE_UNICAST_MAX = 8;
    public static final int EVENT_TYPE_UNICAST_MAX = 9;

    // Broadcast related events
    public static final int EVENT_TYPE_BROADCAST_CREATED = EVENT_TYPE_UNICAST_MAX + 1;
@@ -136,6 +137,8 @@ public class LeAudioStackEvent {
                return "EVENT_TYPE_AUDIO_LOCAL_CODEC_CONFIG_CAPA_CHANGED";
            case EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED:
                return "EVENT_TYPE_AUDIO_GROUP_CODEC_CONFIG_CHANGED";
            case EVENT_TYPE_NATIVE_INITIALIZED:
                return "EVENT_TYPE_NATIVE_INITIALIZED";
            default:
                return "EVENT_TYPE_UNKNOWN:" + type;
        }
Loading