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

Commit 29f38f45 authored by Alice Kuo's avatar Alice Kuo
Browse files

Add getAudioLocation implementation

The change contains
1. Update the sink audio location as it is obtained from the remote device's PACS record
2. Store the audio location in the deviceAudioLocationMap
3. Clear the audio location as device unbonded
4. Support getAudioLocation function to return the sink audio location

Bug: 197199736
Test: build pass
Change-Id: I565f52b3b26afcc4990b5bb89ccc550e7db3607a
parent 6cdc37eb
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@ static jmethodID method_onConnectionStateChanged;
static jmethodID method_onGroupStatus;
static jmethodID method_onGroupNodeStatus;
static jmethodID method_onAudioConf;
static jmethodID method_onSinkAudioLocationAvailable;

static struct {
  jclass clazz;
@@ -129,6 +130,28 @@ class LeAudioClientCallbacksImpl : public LeAudioClientCallbacks {
                                 (jint)sink_audio_location,
                                 (jint)source_audio_location, (jint)avail_cont);
  }

  void OnSinkAudioLocationAvailable(const RawAddress& bd_addr,
                                    uint32_t sink_audio_location) override {
    LOG(INFO) << __func__;

    std::shared_lock<std::shared_timed_mutex> lock(callbacks_mutex);
    CallbackEnv sCallbackEnv(__func__);
    if (!sCallbackEnv.valid() || mCallbacksObj == nullptr) return;

    ScopedLocalRef<jbyteArray> addr(
        sCallbackEnv.get(), sCallbackEnv->NewByteArray(sizeof(RawAddress)));
    if (!addr.get()) {
      LOG(ERROR) << "Failed to new jbyteArray bd addr for group status";
      return;
    }

    sCallbackEnv->SetByteArrayRegion(addr.get(), 0, sizeof(RawAddress),
                                     (jbyte*)&bd_addr);
    sCallbackEnv->CallVoidMethod(mCallbacksObj,
                                 method_onSinkAudioLocationAvailable,
                                 addr.get(), (jint)sink_audio_location);
  }
};

static LeAudioClientCallbacksImpl sLeAudioClientCallbacks;
@@ -145,6 +168,8 @@ static void classInitNative(JNIEnv* env, jclass clazz) {
  method_onGroupNodeStatus =
      env->GetMethodID(clazz, "onGroupNodeStatus", "([BII)V");
  method_onAudioConf = env->GetMethodID(clazz, "onAudioConf", "(IIIII)V");
  method_onSinkAudioLocationAvailable =
      env->GetMethodID(clazz, "onSinkAudioLocationAvailable", "([BI)V");
  method_onConnectionStateChanged =
      env->GetMethodID(clazz, "onConnectionStateChanged", "(I[B)V");
}
+12 −0
Original line number Diff line number Diff line
@@ -141,6 +141,18 @@ public class LeAudioNativeInterface {
        sendMessageToService(event);
    }

    private void onSinkAudioLocationAvailable(byte[] address, int sinkAudioLocation) {
        LeAudioStackEvent event =
                new LeAudioStackEvent(LeAudioStackEvent.EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE);
        event.device = getDevice(address);
        event.valueInt1 = sinkAudioLocation;

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

    /**
     * Initializes the native interface.
     *
+43 −0
Original line number Diff line number Diff line
@@ -143,6 +143,7 @@ public class LeAudioService extends ProfileService {
    private final Map<BluetoothDevice, LeAudioStateMachine> mStateMachines = new LinkedHashMap<>();

    private final Map<BluetoothDevice, Integer> mDeviceGroupIdMap = new ConcurrentHashMap<>();
    private final Map<BluetoothDevice, Integer> mDeviceAudioLocationMap = new ConcurrentHashMap<>();

    private final int mContextSupportingInputAudio =
            BluetoothLeAudio.CONTEXT_TYPE_COMMUNICATION |
@@ -203,6 +204,7 @@ public class LeAudioService extends ProfileService {
        mStateMachinesThread.start();

        mDeviceGroupIdMap.clear();
        mDeviceAudioLocationMap.clear();
        mBroadcastStateMap.clear();
        mBroadcastIdMap.clear();
        mBroadcastMetadataList.clear();
@@ -290,6 +292,7 @@ public class LeAudioService extends ProfileService {
        }

        mDeviceGroupIdMap.clear();
        mDeviceAudioLocationMap.clear();
        mGroupDescriptors.clear();

        if (mBroadcastCallbacks != null) {
@@ -1049,6 +1052,17 @@ public class LeAudioService extends ProfileService {
            intent.putExtra(BluetoothLeAudio.EXTRA_LE_AUDIO_SINK_LOCATION, snk_audio_location);
            intent.putExtra(BluetoothLeAudio.EXTRA_LE_AUDIO_SOURCE_LOCATION, src_audio_location);
            intent.putExtra(BluetoothLeAudio.EXTRA_LE_AUDIO_AVAILABLE_CONTEXTS, available_contexts);
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE) {
            Objects.requireNonNull(stackEvent.device,
                    "Device should never be null, event: " + stackEvent);

            int sink_audio_location = stackEvent.valueInt1;
            mDeviceAudioLocationMap.put(device, sink_audio_location);

            if (DBG) {
                Log.i(TAG, "EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE:" + device
                        + " audio location:" + sink_audio_location);
            }
        } else if (stackEvent.type == LeAudioStackEvent.EVENT_TYPE_GROUP_STATUS_CHANGED) {
            int group_id = stackEvent.valueInt1;
            int group_status = stackEvent.valueInt2;
@@ -1263,6 +1277,7 @@ public class LeAudioService extends ProfileService {
        }

        mDeviceGroupIdMap.remove(device);
        mDeviceAudioLocationMap.remove(device);
        synchronized (mStateMachines) {
            LeAudioStateMachine sm = mStateMachines.get(device);
            if (sm == null) {
@@ -1423,6 +1438,19 @@ public class LeAudioService extends ProfileService {
        return true;
    }

    /**
     * Get device audio location.
     * @param device LE Audio capable device
     * @return the sink audioi location that this device currently exposed
     */
    public int getAudioLocation(BluetoothDevice device) {
        if (device == null) {
            return BluetoothLeAudio.AUDIO_LOCATION_INVALID;
        }
        return mDeviceAudioLocationMap.getOrDefault(device,
                BluetoothLeAudio.AUDIO_LOCATION_INVALID);
    }

    /**
     * Set connection policy of the profile and connects it if connectionPolicy is
     * {@link BluetoothProfile#CONNECTION_POLICY_ALLOWED} or disconnects if connectionPolicy is
@@ -1887,6 +1915,21 @@ public class LeAudioService extends ProfileService {
            }
        }

        @Override
        public void getAudioLocation(BluetoothDevice device, AttributionSource source,
                SynchronousResultReceiver receiver) {
            try {
                LeAudioService service = getService(source);
                int defaultValue = BluetoothLeAudio.AUDIO_LOCATION_INVALID;
                if (service != null) {
                    defaultValue = service.getAudioLocation(device);
                }
                receiver.send(defaultValue);
            } catch (RuntimeException e) {
                receiver.propagateException(e);
            }
        }

        @Override
        public void setConnectionPolicy(BluetoothDevice device, int connectionPolicy,
                AttributionSource source, SynchronousResultReceiver receiver) {
+6 −1
Original line number Diff line number Diff line
@@ -30,8 +30,9 @@ public class LeAudioStackEvent {
    public static final int EVENT_TYPE_GROUP_STATUS_CHANGED = 2;
    public static final int EVENT_TYPE_GROUP_NODE_STATUS_CHANGED = 3;
    public static final int EVENT_TYPE_AUDIO_CONF_CHANGED = 4;
    public static final int EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE = 5;
        // -------- DO NOT PUT ANY NEW UNICAST EVENTS BELOW THIS LINE-------------
    public static final int EVENT_TYPE_UNICAST_MAX = 5;
    public static final int EVENT_TYPE_UNICAST_MAX = 6;

    // Broadcast related events
    public static final int EVENT_TYPE_BROADCAST_CREATED = EVENT_TYPE_UNICAST_MAX + 1;
@@ -103,6 +104,8 @@ public class LeAudioStackEvent {
                return "EVENT_TYPE_GROUP_NODE_STATUS_CHANGED";
            case EVENT_TYPE_AUDIO_CONF_CHANGED:
                return "EVENT_TYPE_AUDIO_CONF_CHANGED";
            case EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE:
                return "EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE";
            case EVENT_TYPE_BROADCAST_CREATED:
                return "EVENT_TYPE_BROADCAST_CREATED";
            case EVENT_TYPE_BROADCAST_DESTROYED:
@@ -138,6 +141,8 @@ public class LeAudioStackEvent {
            case EVENT_TYPE_AUDIO_CONF_CHANGED:
                // FIXME: It should have proper direction names here
                return "{direction:" + value + "}";
            case EVENT_TYPE_SINK_AUDIO_LOCATION_AVAILABLE:
                return "{sink_audio_location:" + value + "}";
            case EVENT_TYPE_BROADCAST_CREATED:
                return "{instance_id:" + value + "}";
            case EVENT_TYPE_BROADCAST_DESTROYED:
+8 −3
Original line number Diff line number Diff line
@@ -1268,9 +1268,14 @@ public final class BluetoothLeAudio implements BluetoothProfile, AutoCloseable {
        if (service == null) {
            Log.w(TAG, "Proxy not attached to service");
            if (DBG) log(Log.getStackTraceString(new Throwable()));
        } else if (mAdapter.isEnabled()) {
            //TODO: add the implementation.
            if (VDBG) log("getAudioLocation() from LE audio service");
        } else if (mAdapter.isEnabled() && isValidDevice(device)) {
            try {
                final SynchronousResultReceiver<Integer> recv = new SynchronousResultReceiver();
                service.getAudioLocation(device, mAttributionSource, recv);
                return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(defaultLocation);
            } catch (RemoteException | TimeoutException e) {
                Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
            }
        }
        return defaultLocation;
    }
Loading