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

Commit a5246dde authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "LeAudioService: Provide Ccid to the native code" am: 0fadcc46

parents b9795bf0 0fadcc46
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -41,6 +41,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;
@@ -127,6 +128,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);
@@ -282,6 +291,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 =
+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);
    }
}
+10 −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);
+69 −0
Original line number Diff line number Diff line
@@ -51,6 +51,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;
@@ -58,6 +59,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;
@@ -118,6 +120,7 @@ public class LeAudioService extends ProfileService {
    ServiceFactory mServiceFactory = new ServiceFactory();

    LeAudioNativeInterface mLeAudioNativeInterface;
    boolean mLeAudioNativeIsInitialized = false;
    LeAudioBroadcasterNativeInterface mLeAudioBroadcasterNativeInterface = null;
    @VisibleForTesting
    AudioManager mAudioManager;
@@ -327,6 +330,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);
@@ -552,6 +556,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);
    }

@@ -562,6 +570,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);
    }

@@ -951,6 +963,10 @@ public class LeAudioService extends ProfileService {
            return;
        }

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

@@ -1336,6 +1352,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) {
@@ -1684,6 +1708,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
@@ -1977,6 +2020,11 @@ public class LeAudioService extends ProfileService {
            return;
        }

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

        mLeAudioNativeInterface.setCodecConfigPreference(groupId,
                                inputCodecConfig, outputCodecConfig);
    }
@@ -2214,6 +2262,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