This is an automated email from the ASF dual-hosted git repository.

rymek pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-nimble.git

commit cf42d74a7041d284892cb717e1a37efa247af2d4
Author: Mariusz Skamra <[email protected]>
AuthorDate: Thu Jan 25 13:30:12 2024 +0100

    nimble/audio: Add initial audio broadcast sink implementation
    
    This adds initial implementation of audio broadcast sink.
---
 nimble/host/audio/include/audio/ble_audio.h        |   98 ++
 .../audio/include/audio/ble_audio_broadcast_sink.h |  281 ++++
 .../audio/include/audio/ble_audio_scan_delegator.h |  393 +++++
 nimble/host/audio/pkg.yml                          |    9 +
 nimble/host/audio/src/ble_audio.c                  |    4 +-
 nimble/host/audio/src/ble_audio_broadcast_sink.c   | 1647 ++++++++++++++++++++
 ...udio_priv.h => ble_audio_broadcast_sink_priv.h} |   15 +-
 nimble/host/audio/src/ble_audio_priv.h             |   11 +
 nimble/host/audio/src/ble_audio_scan_delegator.c   |  460 ++++++
 ...udio_priv.h => ble_audio_scan_delegator_priv.h} |   14 +-
 nimble/host/audio/syscfg.yml                       |   79 +-
 11 files changed, 3001 insertions(+), 10 deletions(-)

diff --git a/nimble/host/audio/include/audio/ble_audio.h 
b/nimble/host/audio/include/audio/ble_audio.h
index 836a1ab5..6fb5f295 100644
--- a/nimble/host/audio/include/audio/ble_audio.h
+++ b/nimble/host/audio/include/audio/ble_audio.h
@@ -68,6 +68,9 @@
 /** Broadcast Audio Broadcast Code Size. */
 #define BLE_AUDIO_BROADCAST_CODE_SIZE                             16
 
+/** Basic Audio Announcement Service UUID. */
+#define BLE_BASIC_AUDIO_ANNOUNCEMENT_SVC_UUID                     0x1851
+
 /** Broadcast Audio Announcement Service UUID. */
 #define BLE_BROADCAST_AUDIO_ANNOUNCEMENT_SVC_UUID                 0x1852
 
@@ -576,6 +579,15 @@ struct ble_audio_broadcast_name {
 /** BLE Audio event: BASS - Set Broadcast Code */
 #define BLE_AUDIO_EVENT_BASS_BROADCAST_CODE_SET              6
 
+/** BLE Audio event: Broadcast Sink - PA Sync state */
+#define BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE         7
+
+/** BLE Audio event: Broadcast Sink - BIS Sync state */
+#define BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE        8
+
+/** BLE Audio event: Broadcast Sink - Metadata Updated */
+#define BLE_AUDIO_EVENT_BROADCAST_SINK_METADATA              9
+
 /** @} */
 
 /** @brief Broadcast Announcement */
@@ -650,6 +662,56 @@ struct ble_audio_event_bass_set_broadcast_code {
     uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE];
 };
 
+enum ble_audio_broadcast_sink_sync_state {
+    /** Broadcast Sink Sync State: Not Synced */
+    BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED,
+
+    /** Broadcast Sink Sync State: Sync initiated */
+    BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED,
+
+    /** Broadcast Sink Sync State: Sync established */
+    BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED,
+};
+
+/** @brief PA Synchronization state */
+struct ble_audio_event_broadcast_sink_pa_sync_state {
+    /** Source ID */
+    uint8_t source_id;
+
+    /** Sync state */
+    enum ble_audio_broadcast_sink_sync_state state;
+};
+
+/** @brief BIS Synchronization state */
+struct ble_audio_event_broadcast_sink_bis_sync_state {
+    /** Source ID */
+    uint8_t source_id;
+
+    /** BIS Index */
+    uint8_t bis_index;
+
+    /** Sync state */
+    enum ble_audio_broadcast_sink_sync_state state;
+
+    /** Connection Handle. Valid if `state` is @ref 
BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED */
+    uint16_t conn_handle;
+};
+
+/** @brief Broadcast Sink Metadata changed */
+struct ble_audio_event_broadcast_sink_metadata {
+    /** Source ID */
+    uint8_t source_id;
+
+    /** BIS Index Mask */
+    uint8_t bis_sync;
+
+    /** Scan Delegator Subgroup: Metadata */
+    const uint8_t *metadata;
+
+    /** Scan Delegator Subgroup: Metadata length */
+    uint8_t metadata_length;
+};
+
 /**
  * Represents a BLE Audio related event. When such an event occurs, the host
  * notifies the application by passing an instance of this structure to an
@@ -715,6 +777,27 @@ struct ble_audio_event {
          * Represents a Broadcast Code baing set in BASS.
          */
         struct ble_audio_event_bass_set_broadcast_code bass_set_broadcast_code;
+
+        /**
+         * @ref BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE
+         *
+         * Represents a update of Broadcast Sink PA sync state.
+         */
+        struct ble_audio_event_broadcast_sink_pa_sync_state 
broadcast_sink_pa_sync_state;
+
+        /**
+         * @ref BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE
+         *
+         * Represents an update of Broadcast Sink BIS sync state.
+         */
+        struct ble_audio_event_broadcast_sink_bis_sync_state 
broadcast_sink_bis_sync_state;
+
+        /**
+         * @ref BLE_AUDIO_EVENT_BROADCAST_SINK_METADATA
+         *
+         * Represents an update in Broadcast Sink Metadata.
+         */
+        struct ble_audio_event_broadcast_sink_metadata broadcast_sink_metadata;
     };
 };
 
@@ -950,6 +1033,21 @@ struct ble_audio_base {
     STAILQ_HEAD(, ble_audio_big_subgroup) subs;
 };
 
+static inline const char *
+ble_audio_broadcast_sink_sync_state_str(enum 
ble_audio_broadcast_sink_sync_state state)
+{
+    switch (state) {
+    case BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED:
+        return "not synced";
+    case BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED:
+        return "initiated";
+    case BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED:
+        return "established";
+    default:
+        return "invalid";
+    }
+}
+
 /** @} */
 
 #endif /* H_BLE_AUDIO_ */
diff --git a/nimble/host/audio/include/audio/ble_audio_broadcast_sink.h 
b/nimble/host/audio/include/audio/ble_audio_broadcast_sink.h
new file mode 100644
index 00000000..36da4e6c
--- /dev/null
+++ b/nimble/host/audio/include/audio/ble_audio_broadcast_sink.h
@@ -0,0 +1,281 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_AUDIO_BROADCAST_SINK_
+#define H_BLE_AUDIO_BROADCAST_SINK_
+
+/**
+ * @file ble_audio_broadcast_sink.h
+ *
+ * @brief Bluetooth LE Audio BAP Broadcast Sink API
+ *
+ * @defgroup ble_audio_broadcast_sink Bluetooth LE Audio BAP Broadcast Sink
+ * @ingroup bt_host
+ * @{
+ *
+ */
+
+#include <stdint.h>
+#include "host/ble_gap.h"
+#include "host/ble_iso.h"
+#include "audio/ble_audio.h"
+#include "audio/ble_audio_scan_delegator.h"
+#include "nimble/ble.h"
+
+enum ble_audio_broadcast_sink_action_type {
+    /** Broadcast Sink Action Type: PA sync */
+    BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC,
+
+    /** Broadcast Sink Action Type: BIG sync */
+    BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC,
+
+    /** Broadcast Sink Action Type: BIS sync */
+    BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC,
+
+    /** Broadcast Sink Action Type: Start discovery (scan) */
+    BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_START,
+
+    /** Broadcast Sink Action Type: Start discovery (scan) */
+    BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_STOP,
+};
+
+struct ble_audio_broadcast_sink_action {
+    /**
+     * Indicates the type of action that is requested.
+     */
+    enum ble_audio_broadcast_sink_action_type type;
+
+    /**
+     * A discriminated union containing additional details concerning the 
action.
+     * The 'type' field indicates which member of the union is valid.
+     */
+    union {
+        /**
+         * Represents PA Sync parameters request.
+         *
+         * The action triggered on locally or remotely initiated PA 
synchronization request.
+         * The application should initialize the `out_parameters`, or abort 
the process.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value to abort.
+         */
+        struct {
+            /** Pointer to Periodic Sync parameters to initialize. */
+            struct ble_gap_periodic_sync_params *out_params;
+        } pa_sync;
+
+        /**
+         * Represents BIG Sync request.
+         *
+         * The action triggered on locally or remotely initiated BIG 
synchronization request.
+         * The application should provide the `out_mse` and `out_sync_timeout`,
+         * or reject the request.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value to abort.
+         */
+        struct {
+            /** Source ID. */
+            uint8_t source_id;
+
+            /** ISO Interval. */
+            uint16_t iso_interval;
+
+            /** Presentation delay. */
+            uint32_t presentation_delay;
+
+            /** Number of SubEvents. The total number of subevents that are 
used to transmit BIS Data. */
+            uint8_t nse;
+
+            /** Burst Number. The number of new payloads for each BIS in a BIS 
event. */
+            uint8_t bn;
+
+            /**
+             * Pointer to Maximum subevents value to initialize.
+             * Range: 0x00 to 0x1F.
+             * Default: 0x00, meaning the Controller can schedule reception of 
any number of subevents up to NSE.
+             */
+            uint8_t *out_mse;
+
+            /**
+             * Pointer to Sync Timeout value to initialize.
+             * Range: 0x000A to 0x4000.
+             * Default: @ref iso_interval * 6.
+             */
+            uint16_t *out_sync_timeout;
+        } big_sync;
+
+        /**
+         * Represents BIS Sync request.
+         *
+         * The action triggered on locally or remotely initiated BIS 
synchronization request.
+         * The application should provide the `out_cb` and optionally 
`out_cb_arg`,
+         * or reject the request.
+         *
+         * @note The `subgroup` object as well as it's `base` object,
+         *       therefore must be copied to in order to cache its information.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value to abort.
+         */
+        struct {
+            /** Source ID. */
+            uint8_t source_id;
+
+            /** Subgroup index. */
+            uint8_t subgroup_index;
+
+            /** Broadcast Audio Source Endpoint BIS. */
+            const struct ble_audio_base_bis *bis;
+
+            /** Broadcast Audio Source Endpoint Subgroup. */
+            const struct ble_audio_base_subgroup *subgroup;
+        } bis_sync;
+
+        /**
+         * Represents discovery start request.
+         *
+         * The action triggered on locally as part of PA synchronization 
process.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_BROADCAST_SINK_ACTION_SCAN_START
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value to abort.
+         */
+        struct {
+            /** Preferred extended discovery parameters. */
+            const struct ble_gap_ext_disc_params *params_preferred;
+        } disc_start;
+    };
+};
+
+/**
+ * Prototype of Broadcast Sink action callback.
+ * This function shall return 0 if operation is accepted, and error code if 
rejected.
+ */
+typedef int ble_audio_broadcast_sink_action_fn(struct 
ble_audio_broadcast_sink_action *action,
+                                               void *arg);
+
+/**
+ * @brief Sets the application callback function.
+ *
+ * This function sets the callback function and its argument that will be 
called
+ * when a Broadcast Sink action is triggered.
+ *
+ * @param cb Pointer to the callback function of type 
ble_audio_scan_delegator_ev_cb.
+ * @param arg Pointer to the argument to be passed to the callback function.
+ *
+ * @return Returns 0 on success, or a non-zero error code otherwise.
+ */
+int ble_audio_broadcast_sink_cb_set(ble_audio_broadcast_sink_action_fn *cb, 
void *arg);
+
+/** Sink Add function parameters */
+struct ble_audio_broadcast_sink_add_params {
+    /** Broadcast Code */
+    uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE];
+
+    /** Broadcast Code parameter is valid */
+    uint8_t broadcast_code_is_valid : 1;
+};
+
+/**
+ * @brief Start audio broadcast sink synchronization with the source.
+ *
+ * This function synchronizes the audio broadcast sink with the source
+ * identified by the given source ID.
+ * The source can be added locally using @ref 
ble_svc_audio_bass_receive_state_add function
+ * or requested by remote device.
+ *
+ * @param source_id             Source ID of Broadcast Source to synchronize 
to.
+ * @param params                Parameters to be used.
+ *
+ * @return                      0 on success;
+ *                              BLE_HS_ENOENT if the source ID is invalid;
+ *                              BLE_HS_EDONE if synced already;
+ *                              BLE_HS_EALREADY if the synchronization is in 
progress;
+ *                              BLE_HS_ENOMEM if memory allocation fails;
+ *                              Any other non-zero value on failure.
+ */
+int ble_audio_broadcast_sink_start(uint8_t source_id,
+                                   const struct 
ble_audio_broadcast_sink_add_params *params);
+
+/**
+ * @brief Stop audio broadcast sink synchronization.
+ *
+ * This function terminates or aborts the pending synchronization with the 
source
+ * identified by the given source ID.
+ *
+ * @param source_id             Source ID of Broadcast Source to synchronize 
to.
+ *
+ * @return                      0 on success;
+ *                              BLE_HS_ENOENT if the source ID is invalid;
+ *                              Any other non-zero value on failure.
+ */
+int ble_audio_broadcast_sink_stop(uint8_t source_id);
+
+/** Metadata Update function parameters */
+struct ble_audio_broadcast_sink_metadata_update_params {
+    /** Subgroup index */
+    uint8_t subgroup_index;
+
+    /** Scan Delegator Subgroup: Metadata */
+    uint8_t *metadata;
+
+    /** Scan Delegator Subgroup: Metadata length */
+    uint8_t metadata_length;
+};
+
+/**
+ * @brief Sets audio broadcast sink metadata.
+ *
+ * This function updates the broadcast sink metadata identified by the given 
source ID.
+ *
+ * @param source_id             Source ID of Broadcast Source.
+ * @param params                Parameters to be used.
+ *
+ * @return                      0 on success;
+ *                              BLE_HS_ENOENT if the source ID is invalid;
+ *                              Any other non-zero value on failure.
+ */
+int ble_audio_broadcast_sink_metadata_update(uint8_t source_id,
+                                             const struct 
ble_audio_broadcast_sink_metadata_update_params *params);
+
+/**
+ * @brief Initialize Broadcast Sink
+ *
+ * This function is restricted to be called by sysinit.
+ *
+ * @return Returns 0 on success, or a non-zero error code otherwise.
+ */
+int ble_audio_broadcast_sink_init(void);
+#endif /* H_BLE_AUDIO_BROADCAST_SINK_ */
diff --git a/nimble/host/audio/include/audio/ble_audio_scan_delegator.h 
b/nimble/host/audio/include/audio/ble_audio_scan_delegator.h
new file mode 100644
index 00000000..5c9aa660
--- /dev/null
+++ b/nimble/host/audio/include/audio/ble_audio_scan_delegator.h
@@ -0,0 +1,393 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_AUDIO_SCAN_DELEGATOR_
+#define H_BLE_AUDIO_SCAN_DELEGATOR_
+
+/**
+ * @file ble_audio_scan_delegator.h
+ *
+ * @brief Bluetooth LE Audio BAP Scan Delegator API
+ *
+ * @defgroup ble_audio_scan_delegator Bluetooth LE Audio BAP Scan Delegator
+ * @ingroup bt_host
+ * @{
+ *
+ */
+
+#include <stdint.h>
+#include "audio/ble_audio.h"
+#include "nimble/ble.h"
+
+#if MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR)
+#define BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX \
+        MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX)
+#else
+#define BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX 0
+#endif /* BLE_AUDIO_SCAN_DELEGATOR */
+
+/** No preferred BIS Synchronization. Decision is left to application. */
+#define BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY       0xFFFFFFFF
+
+/** Unknown PA Interval */
+#define BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_UNKNOWN    0xFFFF
+
+/** Scan Delegator Source descriptor */
+struct ble_audio_scan_delegator_source_desc {
+    /** Scan Delegator Source: BLE Address */
+    ble_addr_t addr;
+
+    /** Scan Delegator Source: Advertising SID */
+    uint8_t adv_sid;
+
+    /** Scan Delegator Source: Broadcast ID */
+    uint32_t broadcast_id;
+};
+
+/** Scan Delegator Broadcast Encryption States */
+enum ble_audio_scan_delegator_big_enc {
+    /** Scan Delegator BIG Encryption: Not Encrypted */
+    BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE,
+
+    /** Scan Delegator BIG Encryption: Broadcast Code Required */
+    BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_MISSING,
+
+    /** Scan Delegator BIG Encryption: Decrypting */
+    BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_DECRYPTING,
+
+    /** Scan Delegator BIG Encryption: Bad Code */
+    BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID
+};
+
+/** Scan Delegator PA Sync States */
+enum ble_audio_scan_delegator_pa_sync_state {
+    /** Scan Delegator PA Sync State: Not synchronized to PA */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NOT_SYNCED,
+
+    /** Scan Delegator PA Sync State: SyncInfo Request */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNC_INFO_REQ,
+
+    /** Scan Delegator PA Sync State: Synchronized to PA */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNCED,
+
+    /** Scan Delegator PA Sync State: Failed to synchronize to PAA */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_ERROR,
+
+    /** Scan Delegator PA Sync State: No PAST */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NO_PAST
+};
+
+/** Scan Delegator Subgroup definition */
+struct ble_audio_scan_delegator_subgroup {
+    /** Scan Delegator Subgroup: BIS Synchronization */
+    uint32_t bis_sync;
+
+    /** Scan Delegator Subgroup: Metadata */
+    uint8_t *metadata;
+
+    /** Scan Delegator Subgroup: Metadata length */
+    uint8_t metadata_length;
+};
+
+/** Scan Delegator PA Sync option */
+enum ble_audio_scan_delegator_pa_sync {
+    /** Scan Delegator PA Sync: Do not synchronize to PA */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_DO_NOT_SYNC,
+
+    /** Scan Delegator PA Sync: Synchronize to PA – PAST available */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_PAST_AVAILABLE,
+
+    /** Scan Delegator PA Sync: Synchronize to PA – PAST not available */
+    BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_PAST_NOT_AVAILABLE,
+};
+
+/** Scan Delegator Broadcast Source Synchronization option */
+struct ble_audio_scan_delegator_sync_opt {
+    /** PA Sync option */
+    enum ble_audio_scan_delegator_pa_sync pa_sync;
+
+    /** PA Sync interval */
+    uint16_t pa_interval;
+
+    /** Number of Subgroups */
+    uint8_t num_subgroups;
+
+    /** Subgroup sync option */
+    struct ble_audio_scan_delegator_subgroup subgroups[
+        BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX];
+};
+
+enum ble_audio_scan_delegator_action_type {
+    /** Scan Delegator Action Type: Add Source */
+    BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD,
+
+    /** Scan Delegator Action Type: Modify Source */
+    BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY,
+
+    /** Scan Delegator Action Type: Remove Source */
+    BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE,
+};
+
+struct ble_audio_scan_delegator_action {
+    /**
+     * Indicates the type of action that is requested.
+     */
+    enum ble_audio_scan_delegator_action_type type;
+
+    /**
+     * A union containing additional details concerning the action.
+     * The 'type' field indicates which member of the union is valid.
+     */
+    union {
+        /**
+         * Represents remote Add Source operation request.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD
+         *
+         * @note The @ref ble_audio_scan_delegator_subgroup.metadata object is 
temporary, therefore must be copied to in
+         *       order to cache its information.
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value to reject.
+         */
+        struct {
+            /** Source ID */
+            uint8_t source_id;
+
+            /** Broadcast Source descriptor */
+            struct ble_audio_scan_delegator_source_desc source_desc;
+
+            /** Broadcast synchronization option */
+            struct ble_audio_scan_delegator_sync_opt sync_opt;
+
+            /**
+             * Valid pointer to provide source ID to be swapped or NULL.
+             *
+             * If there are insufficient resources to handle the operation, 
the application is requested to provide
+             * source ID to be removed once accepted.
+             */
+            uint8_t *out_source_id_to_swap;
+        } source_add;
+
+        /**
+         * Represents remote Modify Source operation request.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY
+         *
+         * @note The @ref ble_audio_scan_delegator_subgroup.metadata object is 
temporary, therefore must be copied to in
+         *       order to cache its information.
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value to reject.
+         */
+        struct {
+            /** Source ID */
+            uint8_t source_id;
+
+            /** Broadcast synchronization option */
+            struct ble_audio_scan_delegator_sync_opt sync_opt;
+        } source_modify;
+
+        /**
+         * Represents remote Remove Source operation request.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value to reject.
+         */
+        struct {
+            /** Source ID */
+            uint8_t source_id;
+        } source_remove;
+
+        /**
+         * Represents remote Broadcast Code Set operation request.
+         *
+         * Valid for the following action types:
+         *     o BLE_AUDIO_SCAN_DELEGATOR_ACTION_BROADCAST_CODE
+         *
+         * Return:
+         *     o 0 on success;
+         *     o A non-zero value on failure.
+         */
+        struct {
+            /** Source ID */
+            uint8_t source_id;
+
+            /** Broadcast Code value to be stored. */
+            const uint8_t value[BLE_AUDIO_BROADCAST_CODE_SIZE];
+        } broadcast_code;
+    };
+};
+
+/**
+ * Prototype of Scan Delegator action callback.
+ * This function shall return 0 if operation is accepted, and error code if 
rejected.
+ */
+typedef int ble_audio_scan_delegator_action_fn(
+    struct ble_audio_scan_delegator_action *action, void *arg);
+
+/**
+ * @brief Sets the application callback function.
+ *
+ * This function sets the callback function that will be called on remote 
device request.
+ *
+ * @param[in] cb                Pointer to the callback function.
+ * @param[in] arg               Pointer to any additional arguments that need 
to
+ *                              be passed to the callback function.
+ *
+ * @return                      0 on success;
+ *                              A non-zero value on failure.
+ */
+int ble_audio_scan_delegator_action_fn_set(ble_audio_scan_delegator_action_fn 
*cb, void *arg);
+
+/** Scan Delegator Receive State definition */
+struct ble_audio_scan_delegator_receive_state {
+    /** Scan Delegator Receive State: PA Sync state */
+    enum ble_audio_scan_delegator_pa_sync_state pa_sync_state;
+
+    /** Scan Delegator Receive State: BIG Encryption */
+    enum ble_audio_scan_delegator_big_enc big_enc;
+
+    /**
+     * Incorrect Bad Broadcast Code.
+     * Valid for @ref BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID.
+     */
+    uint8_t bad_code[BLE_AUDIO_BROADCAST_CODE_SIZE];
+
+    /** Scan Delegator Receive State: Number of subgroups */
+    uint8_t num_subgroups;
+
+    /** Scan Delegator Receive State: subgroup entries */
+    struct ble_audio_scan_delegator_subgroup subgroups[
+        MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX)];
+};
+
+/** Receive State Add function parameters */
+struct ble_audio_scan_delegator_receive_state_add_params {
+    /** Broadcast Source descriptor */
+    struct ble_audio_scan_delegator_source_desc source_desc;
+
+    /** Receive state */
+    struct ble_audio_scan_delegator_receive_state state;
+};
+
+/**
+ * @brief Adds the receive state.
+ *
+ * This function allocates receive state and returns it's source ID.
+ *
+ * @param[in] params                Parameters to be used.
+ * @param[in,out] source_id         Unique source ID of receive state added.
+ *
+ * @return                      0 on success;
+ *                              A non-zero value on failure.
+ */
+int ble_audio_scan_delegator_receive_state_add(const struct 
ble_audio_scan_delegator_receive_state_add_params *params,
+                                               uint8_t *source_id);
+
+/**
+ * @brief Removes the receive state.
+ *
+ * This function removes the specific receive state identified by source ID.
+ *
+ * @param[in] source_id         Source ID of receive state to be removed.
+ * @param[in] params            Parameters to be used.
+ *
+ * @return                      0 on success;
+ *                              A non-zero value on failure.
+ */
+int ble_audio_scan_delegator_receive_state_remove(uint8_t source_id);
+
+/**
+ * @brief Set the receive state.
+ *
+ * This function updates the specific receive state identified by source ID.
+ *
+ * @param[in] source_id         Source ID of receive state to be updated.
+ * @param[in] state             Receive state to be set.
+ *
+ * @return                      0 on success;
+ *                              A non-zero value on failure.
+ */
+int ble_audio_scan_delegator_receive_state_set(uint8_t source_id,
+                                               const struct 
ble_audio_scan_delegator_receive_state *state);
+
+/**
+ * @brief get the receive state.
+ *
+ * This function returns the specific receive state identified by source ID.
+ *
+ * @param[in] source_id         Source ID of receive state to be updated.
+ * @param[in,out] state         Pointer to receive state to be populate.
+ *
+ * @return                      0 on success;
+ *                              A non-zero value on failure.
+ */
+int ble_audio_scan_delegator_receive_state_get(uint8_t source_id,
+                                               struct 
ble_audio_scan_delegator_receive_state *state);
+
+/** Scan Delegator Receive State entry definition */
+struct ble_audio_scan_delegator_receive_state_entry {
+    /** Source ID */
+    uint8_t source_id;
+
+    /** Broadcast Source descriptor */
+    struct ble_audio_scan_delegator_source_desc source_desc;
+
+    /** Receive state */
+    struct ble_audio_scan_delegator_receive_state state;
+};
+
+/**
+ * Type definition Receive State iteration callback function.
+ *
+ * @note Return 0 to continue, or a non-zero to abort foreach loop.
+ */
+typedef int ble_audio_scan_delegator_receive_state_foreach_fn(
+    struct ble_audio_scan_delegator_receive_state_entry *entry, void *arg);
+
+/**
+ * @brief Iterate receive states.
+ *
+ * @param[in] cb                Callback to be called on codec entries.
+ * @param[in] arg               Optional callback argument.
+ *
+ * @return                      0 on success;
+ *                              A non-zero value on failure.
+ */
+void 
ble_audio_scan_delegator_receive_state_foreach(ble_audio_scan_delegator_receive_state_foreach_fn
 *cb, void *arg);
+
+/**
+ * @brief Initialize Scan Delegator
+ *
+ * This function is restricted to be called by sysinit.
+ *
+ * @return                      0 on success;
+ *                              A non-zero value on failure.
+ */
+int ble_audio_scan_delegator_init(void);
+#endif /* H_BLE_AUDIO_SCAN_DELEGATOR_ */
diff --git a/nimble/host/audio/pkg.yml b/nimble/host/audio/pkg.yml
index 66d418d3..5dd14616 100644
--- a/nimble/host/audio/pkg.yml
+++ b/nimble/host/audio/pkg.yml
@@ -30,3 +30,12 @@ pkg.keywords:
 pkg.deps:
     - nimble
     - nimble/host
+
+pkg.deps.BLE_AUDIO_SCAN_DELEGATOR:
+    - nimble/host/audio/services/bass
+
+pkg.init.BLE_AUDIO_BROADCAST_SINK:
+    ble_audio_broadcast_sink_init: 
'MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_SYSINIT_STAGE)'
+
+pkg.init.BLE_AUDIO_SCAN_DELEGATOR:
+    ble_audio_scan_delegator_init: 
'MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SYSINIT_STAGE)'
diff --git a/nimble/host/audio/src/ble_audio.c 
b/nimble/host/audio/src/ble_audio.c
index 42533478..f601a07f 100644
--- a/nimble/host/audio/src/ble_audio.c
+++ b/nimble/host/audio/src/ble_audio.c
@@ -136,7 +136,9 @@ ble_audio_gap_event(struct ble_gap_event *gap_event, void 
*arg)
 {
     switch (gap_event->type) {
     case BLE_GAP_EVENT_EXT_DISC: {
-        struct ble_audio_adv_parse_broadcast_announcement_data data = { 0 };
+        struct ble_audio_adv_parse_broadcast_announcement_data data = {
+            .success = false,
+        };
         int rc;
 
         rc = ble_hs_adv_parse(gap_event->ext_disc.data,
diff --git a/nimble/host/audio/src/ble_audio_broadcast_sink.c 
b/nimble/host/audio/src/ble_audio_broadcast_sink.c
new file mode 100644
index 00000000..8c2f0545
--- /dev/null
+++ b/nimble/host/audio/src/ble_audio_broadcast_sink.c
@@ -0,0 +1,1647 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "sysinit/sysinit.h"
+
+#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)
+#include "stdlib.h"
+
+#include "audio/ble_audio.h"
+#include "audio/ble_audio_broadcast_sink.h"
+#include "audio/ble_audio_scan_delegator.h"
+#include "host/ble_gap.h"
+#include "host/ble_hs.h"
+#include "host/ble_iso.h"
+#include "host/ble_uuid.h"
+
+#include "ble_audio_priv.h"
+#include "ble_audio_scan_delegator_priv.h"
+
+#define CLAMP(_n, _min, _max)                   (MAX(_min, MIN(_n, _max)))
+#define BROADCAST_ID_INVALID                    0xFFFFFFFF
+#define BIS_INDEX_TEST(_bis_sync, _index)       (((_bis_sync) & (1 << 
((_index) - 1))) > 0)
+#define BIS_INDEX_SET(_bis_sync, _index)        ((_bis_sync) |= (1 << 
((_index) - 1)))
+#define BIS_INDEX_CLEAR(_bis_sync, _index)      ((_bis_sync) &= ~(1 << 
((_index) - 1)))
+
+static struct {
+    ble_audio_broadcast_sink_action_fn *fn;
+    void *arg;
+} action_cb;
+
+enum pa_sync_state_internal {
+    PA_SYNC_STATE_IDLE,
+    PA_SYNC_STATE_PENDING_DISC,
+    PA_SYNC_STATE_PENDING_PAST,
+    PA_SYNC_STATE_PENDING_SYNC,
+    PA_SYNC_STATE_ACTIVE,
+    PA_SYNC_STATE_ERROR,
+    PA_SYNC_STATE_TIMEOUT,
+};
+
+enum big_sync_state_internal {
+    BIG_SYNC_STATE_IDLE,
+    BIG_SYNC_STATE_PENDING_BIG_INFO,
+    BIG_SYNC_STATE_PENDING_CODE,
+    BIG_SYNC_STATE_PENDING_BASE,
+    BIG_SYNC_STATE_PENDING_SYNC,
+    BIG_SYNC_STATE_FAILED,
+    BIG_SYNC_STATE_ACTIVE,
+};
+
+struct ble_audio_broadcast_sink {
+    /** Instance ID, same as BASS Source ID */
+    uint8_t source_id;
+
+    /** Internal PA sync state */
+    enum pa_sync_state_internal pa_sync_state;
+
+    /** Internal BIG sync state */
+    enum big_sync_state_internal big_sync_state;
+
+    /** Periodic sync handle */
+    uint16_t pa_sync_handle;
+
+    /** Connection handle or @ref BLE_HS_CONN_HANDLE_NONE */
+    uint16_t past_conn_handle;
+
+    /** BIG Handle */
+    uint8_t big_handle;
+
+    /** ISO Interval */
+    uint16_t iso_interval;
+
+    /** Burst Number */
+    uint8_t bn;
+
+    /** Number of SubEvents */
+    uint8_t nse;
+
+    /** Callback function */
+    ble_audio_event_fn *cb;
+
+    /** Broadcast code */
+    uint8_t broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE];
+
+    /** The optional argument to pass to the callback function. */
+    void *cb_arg;
+
+    /** BIG Sync Parameters */
+    struct ble_audio_broadcast_sink_big_sync_params *big_sync_params;
+
+    /** If true, the broadcast is encrypted and requires broadcast_code */
+    uint8_t is_encrypted : 1;
+    /** If true, the broadcast_code value is valid */
+    uint8_t broadcast_code_is_valid : 1;
+
+    /** Internal subgroups state */
+    uint8_t num_subgroups;
+    struct {
+        uint32_t bis_sync;
+    } subgroups[MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX)];
+
+    /** Singly-linked list entry. */
+    SLIST_ENTRY(ble_audio_broadcast_sink) next;
+};
+
+static SLIST_HEAD(, ble_audio_broadcast_sink) ble_audio_broadcast_sink_list;
+static struct os_mempool ble_audio_broadcast_sink_pool;
+static os_membuf_t ble_audio_broadcast_sink_mem[
+    OS_MEMPOOL_SIZE(MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_MAX),
+                    sizeof(struct ble_audio_broadcast_sink))];
+
+/** If true, the discovery was started by us, otherwise by someone else */
+static bool disc_self_initiated;
+
+/** If true, the Periodic Advertising Sync is pending */
+static bool periodic_adv_sync_in_progress;
+
+static int gap_event_handler(struct ble_gap_event *event, void *arg);
+static int iso_event_handler(struct ble_iso_event *event, void *arg);
+static void big_sync_state_set(struct ble_audio_broadcast_sink *sink, enum 
big_sync_state_internal state_internal);
+static void pa_sync_state_set(struct ble_audio_broadcast_sink *sink, enum 
pa_sync_state_internal state_internal);
+
+static struct ble_audio_broadcast_sink *
+broadcast_sink_get(uint8_t source_id)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) {
+        if (source_id == sink->source_id) {
+            return sink;
+        }
+    }
+
+    return NULL;
+}
+
+static struct ble_audio_broadcast_sink *
+broadcast_lookup_pa_sync_handle(uint16_t pa_sync_handle)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) {
+        if (pa_sync_handle == sink->pa_sync_handle) {
+            return sink;
+        }
+    }
+
+    return NULL;
+}
+
+static struct ble_audio_broadcast_sink *
+broadcast_sink_lookup_adv_sid_broadcast_id_pair(uint8_t adv_sid, uint32_t 
broadcast_id)
+{
+    struct ble_audio_scan_delegator_source_desc source_desc;
+    struct ble_audio_broadcast_sink *sink;
+    int rc;
+
+    SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) {
+        rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, 
&source_desc);
+        if (rc != 0) {
+            BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc);
+            continue;
+        }
+
+        if (source_desc.adv_sid == adv_sid && source_desc.broadcast_id == 
broadcast_id) {
+            return sink;
+        }
+    }
+
+    return NULL;
+}
+
+static struct ble_audio_broadcast_sink *
+broadcast_sink_lookup_addr_adv_sid_pair(const ble_addr_t *addr, uint8_t 
adv_sid)
+{
+    struct ble_audio_scan_delegator_source_desc source_desc;
+    struct ble_audio_broadcast_sink *sink;
+    int rc;
+
+    SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) {
+        rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, 
&source_desc);
+        if (rc != 0) {
+            BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc);
+            continue;
+        }
+
+        if (source_desc.adv_sid == adv_sid && ble_addr_cmp(&source_desc.addr, 
addr) == 0) {
+            return sink;
+        }
+    }
+
+    return NULL;
+}
+
+static struct ble_audio_broadcast_sink *
+broadcast_sink_lookup_pa_sync_state(enum pa_sync_state_internal state_internal)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    SLIST_FOREACH(sink, &ble_audio_broadcast_sink_list, next) {
+        if (sink->pa_sync_state == state_internal) {
+            return sink;
+        }
+    }
+
+    return NULL;
+}
+
+static int
+disc_start(void)
+{
+    struct ble_audio_broadcast_sink_action action;
+    struct ble_gap_ext_disc_params disc_params;
+    int rc;
+
+    if (ble_gap_disc_active()) {
+        return 0;
+    }
+
+    disc_params.itvl = BLE_GAP_SCAN_FAST_INTERVAL_MIN;
+    disc_params.window = BLE_GAP_SCAN_FAST_WINDOW;
+    disc_params.passive = true;
+
+    action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_START;
+    action.disc_start.params_preferred = &disc_params;
+
+    rc = action_cb.fn(&action, action_cb.arg);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("disc start rejected by user (%d)\n", rc);
+    } else {
+        disc_self_initiated = true;
+    }
+
+    return rc;
+}
+
+static void
+disc_stop(void)
+{
+    struct ble_audio_broadcast_sink_action action;
+    int rc;
+
+    if (!disc_self_initiated || !ble_gap_disc_active()) {
+        return;
+    }
+
+    action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_DISC_STOP;
+
+    rc = action_cb.fn(&action, action_cb.arg);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("disc stop rejected by user (%d)\n", rc);
+    }
+
+    disc_self_initiated = false;
+}
+
+struct basic_audio_announcement_svc_data {
+    /** BASE length */
+    uint8_t length;
+
+    /** BASE */
+    const uint8_t *base;
+};
+
+struct service_data_uuid16 {
+    struct basic_audio_announcement_svc_data basic_audio_announcement;
+};
+
+static void
+service_data_uuid16_parse(const uint16_t uuid16, const uint8_t * const value, 
const uint8_t value_len,
+                          void *user_data)
+{
+    struct service_data_uuid16 *data = user_data;
+
+    if (uuid16 == BLE_BASIC_AUDIO_ANNOUNCEMENT_SVC_UUID) {
+        data->basic_audio_announcement.base = value;
+        data->basic_audio_announcement.length = value_len;
+    }
+}
+
+struct periodic_report {
+    struct service_data_uuid16 uuid16;
+};
+
+static int
+periodic_report_parse(const struct ble_hs_adv_field *field, void *user_data)
+{
+    struct periodic_report *report = user_data;
+    const uint8_t value_len = field->length - sizeof(field->length);
+    ble_uuid16_t uuid16 = BLE_UUID16_INIT(0);
+    uint8_t offset = 0;
+
+    switch (field->type) {
+    case BLE_HS_ADV_TYPE_SVC_DATA_UUID16:
+        if (value_len < 2) {
+            break;
+        }
+
+        uuid16.value = get_le16(&field->value[offset]);
+        offset += 2;
+
+        service_data_uuid16_parse(uuid16.value, &field->value[offset], 
value_len - offset, &report->uuid16);
+        break;
+
+    default:
+        /* Continue */
+        return BLE_HS_ENOENT;
+    }
+
+    /* Stop */
+    return 0;
+}
+
+static uint32_t
+subgroup_bis_sync_get(struct ble_audio_broadcast_sink *sink, uint8_t 
subgroup_index)
+{
+    if (subgroup_index > sink->num_subgroups) {
+        return 0;
+    }
+
+    return sink->subgroups[subgroup_index].bis_sync;
+}
+
+static void
+bass_big_state_update(struct ble_audio_broadcast_sink *sink, enum 
big_sync_state_internal from,
+                      enum big_sync_state_internal to)
+{
+    struct ble_audio_scan_delegator_receive_state receive_state = {0};
+    int rc;
+
+    rc = ble_audio_scan_delegator_receive_state_get(sink->source_id, 
&receive_state);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("receive state get failed (%d)\n", rc);
+        return;
+    }
+
+    switch (to) {
+    case BIG_SYNC_STATE_PENDING_CODE:
+        receive_state.big_enc = 
BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_MISSING;
+        break;
+
+    case BIG_SYNC_STATE_IDLE:
+        if (from == BIG_SYNC_STATE_PENDING_CODE) {
+            /* FIXME: this does not seem to be right */
+            receive_state.big_enc = 
BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID;
+            memcpy(receive_state.bad_code, sink->broadcast_code, 
sizeof(receive_state.bad_code));
+        } else if (from == BIG_SYNC_STATE_ACTIVE || from == 
BIG_SYNC_STATE_FAILED) {
+            /* Iterate subgroup indexes to update the BIS Sync state */
+            for (uint8_t index = 0; index < receive_state.num_subgroups; 
index++) {
+                receive_state.subgroups[index].bis_sync = 0;
+            }
+        }
+    /* fallthrough */
+
+    case BIG_SYNC_STATE_PENDING_BIG_INFO:
+    case BIG_SYNC_STATE_PENDING_BASE:
+    case BIG_SYNC_STATE_PENDING_SYNC:
+        receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE;
+        break;
+
+    case BIG_SYNC_STATE_FAILED:
+        receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE;
+
+        /* BASS v1.0 3.1.1.4 Add Source operation
+         * "(...) if the server fails to synchronize to the BIG, the server 
shall write a value of
+         * 0xFFFFFFFF (Failed to synchronize to BIG) to the BIS_Sync_State 
field
+         */
+        for (uint8_t index = 0; index < receive_state.num_subgroups; index++) {
+            receive_state.subgroups[index].bis_sync = 
BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY;
+        }
+        break;
+
+    case BIG_SYNC_STATE_ACTIVE:
+        if (sink->is_encrypted) {
+            receive_state.big_enc = 
BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_DECRYPTING;
+        } else {
+            receive_state.big_enc = BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_NONE;
+        }
+
+        /* Iterate subgroup indexes to update the BIS Sync state */
+        for (uint8_t index = 0; index < receive_state.num_subgroups; index++) {
+            receive_state.subgroups[index].bis_sync = 
subgroup_bis_sync_get(sink, index);
+        }
+        break;
+    }
+
+    rc = ble_audio_scan_delegator_receive_state_set(sink->source_id, 
&receive_state);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("receive state update failed (%d)\n", rc);
+    }
+}
+
+static enum ble_audio_broadcast_sink_sync_state
+big_state_internal_to_api(enum big_sync_state_internal state_internal)
+{
+    switch (state_internal) {
+    case BIG_SYNC_STATE_PENDING_CODE:
+    case BIG_SYNC_STATE_PENDING_BIG_INFO:
+    case BIG_SYNC_STATE_PENDING_BASE:
+    case BIG_SYNC_STATE_PENDING_SYNC:
+        return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED;
+
+    case BIG_SYNC_STATE_ACTIVE:
+        return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED;
+
+    default:
+        return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED;
+    }
+}
+
+static void
+api_bis_state_update(struct ble_audio_broadcast_sink *sink, enum 
big_sync_state_internal from,
+                     enum big_sync_state_internal to)
+{
+    struct ble_audio_event event;
+
+    if (to == BIG_SYNC_STATE_ACTIVE) {
+        /* special case. event already sent from 
big_sync_established_handler() */
+        return;
+    }
+
+    event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE;
+    event.broadcast_sink_bis_sync_state.source_id = sink->source_id;
+    event.broadcast_sink_bis_sync_state.state = big_state_internal_to_api(to);
+    event.broadcast_sink_bis_sync_state.conn_handle = BLE_HS_CONN_HANDLE_NONE;
+
+    for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; 
subgroup_index++) {
+        uint32_t bis_sync = sink->subgroups[subgroup_index].bis_sync;
+
+        if (bis_sync != BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY) {
+            for (uint8_t bis_index = 0; bis_sync > 0; bis_index++) {
+                if (BIS_INDEX_TEST(bis_sync, bis_index)) {
+                    event.broadcast_sink_bis_sync_state.bis_index = bis_index;
+                    ble_audio_event_listener_call(&event);
+                    BIS_INDEX_CLEAR(bis_sync, bis_index);
+                }
+            }
+        }
+    }
+}
+
+static void
+big_sync_state_set(struct ble_audio_broadcast_sink *sink, enum 
big_sync_state_internal state_internal)
+{
+    enum big_sync_state_internal state_internal_old = sink->big_sync_state;
+
+    if (state_internal == state_internal_old) {
+        return;
+    }
+
+    sink->big_sync_state = state_internal;
+
+    api_bis_state_update(sink, state_internal_old, state_internal);
+    bass_big_state_update(sink, state_internal_old, state_internal);
+}
+
+static void
+bass_pa_state_update(struct ble_audio_broadcast_sink *sink, enum 
pa_sync_state_internal from,
+                     enum pa_sync_state_internal to)
+{
+    struct ble_audio_scan_delegator_receive_state receive_state;
+    int rc;
+
+    rc = ble_audio_scan_delegator_receive_state_get(sink->source_id, 
&receive_state);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("receive state get failed (%d)\n", rc);
+        return;
+    }
+
+    switch (to) {
+    case PA_SYNC_STATE_IDLE:
+    case PA_SYNC_STATE_PENDING_DISC:
+    case PA_SYNC_STATE_PENDING_SYNC:
+        receive_state.pa_sync_state = 
BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NOT_SYNCED;
+        break;
+
+    case PA_SYNC_STATE_PENDING_PAST:
+        receive_state.pa_sync_state = 
BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNC_INFO_REQ;
+        break;
+
+    case PA_SYNC_STATE_ACTIVE:
+        receive_state.pa_sync_state = 
BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_SYNCED;
+        break;
+
+    case PA_SYNC_STATE_ERROR:
+        receive_state.pa_sync_state = 
BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_ERROR;
+        break;
+
+    case PA_SYNC_STATE_TIMEOUT:
+        if (from == PA_SYNC_STATE_PENDING_PAST) {
+            receive_state.pa_sync_state = 
BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_NO_PAST;
+        } else {
+            receive_state.pa_sync_state = 
BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_STATE_ERROR;
+        }
+        break;
+    }
+
+    rc = ble_audio_scan_delegator_receive_state_set(sink->source_id, 
&receive_state);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("receive state set failed (%d)\n", rc);
+    }
+}
+
+static enum ble_audio_broadcast_sink_sync_state
+pa_state_internal_to_api(enum pa_sync_state_internal state_internal)
+{
+    switch (state_internal) {
+    case PA_SYNC_STATE_PENDING_DISC:
+    case PA_SYNC_STATE_PENDING_SYNC:
+    case PA_SYNC_STATE_PENDING_PAST:
+        return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_INITIATED;
+
+    case PA_SYNC_STATE_ACTIVE:
+        return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED;
+
+    default:
+        return BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED;
+    }
+}
+
+static void
+api_pa_state_update(struct ble_audio_broadcast_sink *sink, enum 
pa_sync_state_internal from,
+                    enum pa_sync_state_internal to)
+{
+    struct ble_audio_event event;
+
+    event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_PA_SYNC_STATE;
+    event.broadcast_sink_pa_sync_state.source_id = sink->source_id;
+    event.broadcast_sink_pa_sync_state.state = pa_state_internal_to_api(to);
+
+    if (event.broadcast_sink_pa_sync_state.state != 
pa_state_internal_to_api(from)) {
+        ble_audio_event_listener_call(&event);
+    }
+}
+
+static void
+pa_sync_state_set(struct ble_audio_broadcast_sink *sink, enum 
pa_sync_state_internal state_internal)
+{
+    enum pa_sync_state_internal state_internal_old = sink->pa_sync_state;
+
+    if (state_internal == state_internal_old) {
+        return;
+    }
+
+    sink->pa_sync_state = state_internal;
+    api_pa_state_update(sink, state_internal_old, state_internal);
+    bass_pa_state_update(sink, state_internal_old, state_internal);
+}
+
+static uint32_t
+group_bis_sync_get(struct ble_audio_broadcast_sink *sink)
+{
+    uint32_t bis_sync_flat = 0;
+
+    for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; 
subgroup_index++) {
+        bis_sync_flat |= sink->subgroups[subgroup_index].bis_sync;
+    }
+
+    return bis_sync_flat;
+}
+
+static void
+pa_sync_create(void)
+{
+    struct ble_gap_periodic_sync_params periodic_sync_params = {0};
+    struct ble_audio_broadcast_sink_action action;
+    int rc;
+
+    if (periodic_adv_sync_in_progress) {
+        return;
+    }
+
+    action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC;
+    action.pa_sync.out_params = &periodic_sync_params;
+
+    rc = action_cb.fn(&action, action_cb.arg);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("rejected by user (%d)\n", rc);
+        return;
+    }
+
+    rc = ble_gap_periodic_adv_sync_create(NULL, 0, &periodic_sync_params,
+                                          gap_event_handler, NULL);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("adv sync create failed (%d)\n", rc);
+    } else {
+        periodic_adv_sync_in_progress = true;
+    }
+}
+
+static void
+big_sync_established_handler(uint8_t source_id, uint8_t status, const struct 
ble_iso_big_desc *desc)
+{
+    struct ble_audio_broadcast_sink *sink;
+    uint32_t bis_sync_state = 0;
+    uint32_t group_bis_sync;
+    uint8_t bis_index;
+
+    /* Restart scan if needed */
+    if (broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_SYNC) != 
NULL) {
+        pa_sync_create();
+        disc_start();
+    } else if (broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_DISC) 
!= NULL) {
+        disc_start();
+    }
+
+    sink = broadcast_sink_get(source_id);
+    if (sink == NULL) {
+        BLE_HS_LOG_DEBUG("Unknown source_id %u\n", source_id);
+        return;
+    }
+
+    if (status != 0) {
+        big_sync_state_set(sink, BIG_SYNC_STATE_FAILED);
+        return;
+    }
+
+    bis_index = 0;
+    group_bis_sync = group_bis_sync_get(sink);
+
+    for (uint8_t i = 0; i < desc->num_bis; i++) {
+        uint16_t conn_handle = desc->conn_handle[i];
+
+        for (; group_bis_sync > 0; bis_index++) {
+            if (BIS_INDEX_TEST(group_bis_sync, bis_index)) {
+                struct ble_audio_event event;
+
+                event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE;
+                event.broadcast_sink_bis_sync_state.source_id = 
sink->source_id;
+                event.broadcast_sink_bis_sync_state.bis_index = bis_index;
+                event.broadcast_sink_bis_sync_state.state = 
BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_ESTABLISHED;
+                event.broadcast_sink_bis_sync_state.conn_handle = conn_handle;
+
+                ble_audio_event_listener_call(&event);
+
+                BIS_INDEX_SET(bis_sync_state, bis_index);
+                BIS_INDEX_CLEAR(group_bis_sync, bis_index);
+                break;
+            }
+        }
+    }
+
+    /* Check whether all BISes got conn handle */
+    group_bis_sync = group_bis_sync_get(sink);
+    if (bis_sync_state != group_bis_sync) {
+        BLE_HS_LOG_WARN("not all BISes synced");
+
+        for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; 
subgroup_index++) {
+            uint32_t bis_sync_missing;
+
+            bis_sync_missing = sink->subgroups[subgroup_index].bis_sync & 
~bis_sync_state;
+            if (bis_sync_missing == 0) {
+                continue;
+            }
+
+            for (bis_index = 0; bis_sync_missing > 0; bis_index++) {
+                if (BIS_INDEX_TEST(bis_sync_missing, bis_index)) {
+                    struct ble_audio_event event;
+
+                    event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_BIS_SYNC_STATE;
+                    event.broadcast_sink_bis_sync_state.source_id = 
sink->source_id;
+                    event.broadcast_sink_bis_sync_state.bis_index = bis_index;
+                    event.broadcast_sink_bis_sync_state.state = 
BLE_AUDIO_BROADCAST_SINK_SYNC_STATE_NOT_SYNCED;
+                    event.broadcast_sink_bis_sync_state.conn_handle = 
BLE_HS_CONN_HANDLE_NONE;
+
+                    ble_audio_event_listener_call(&event);
+
+                    BIS_INDEX_CLEAR(bis_sync_missing, bis_index);
+                }
+            }
+
+            sink->subgroups[subgroup_index].bis_sync &= bis_sync_state;
+        }
+    }
+
+    big_sync_state_set(sink, BIG_SYNC_STATE_ACTIVE);
+}
+
+static void
+big_sync_terminated_handler(uint8_t source_id, uint8_t reason)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    sink = broadcast_sink_get(source_id);
+    if (sink == NULL) {
+        BLE_HS_LOG_DEBUG("Unknown source_id %u\n", source_id);
+        return;
+    }
+
+    big_sync_state_set(sink, BIG_SYNC_STATE_IDLE);
+}
+
+static int
+iso_event_handler(struct ble_iso_event *event, void *arg)
+{
+    switch (event->type) {
+    case BLE_ISO_EVENT_BIG_SYNC_ESTABLISHED:
+        big_sync_established_handler(POINTER_TO_UINT(arg), 
event->big_sync_established.status,
+                                     &event->big_sync_established.desc);
+        break;
+
+    case BLE_ISO_EVENT_BIG_SYNC_TERMINATED:
+        big_sync_terminated_handler(POINTER_TO_UINT(arg), 
event->big_terminated.reason);
+        break;
+
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+static int
+pa_sync_create_cancel(void)
+{
+    int rc;
+
+    if (!periodic_adv_sync_in_progress) {
+        return 0;
+    }
+
+    rc = ble_gap_periodic_adv_sync_create_cancel();
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("adv sync create cancel failed (%d)\n", rc);
+    } else {
+        periodic_adv_sync_in_progress = false;
+    }
+
+    return rc;
+}
+
+static int
+pa_sync_add(const ble_addr_t *addr, uint8_t adv_sid)
+{
+    int rc;
+
+    if (periodic_adv_sync_in_progress) {
+        rc = pa_sync_create_cancel();
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    rc = ble_gap_add_dev_to_periodic_adv_list(addr, adv_sid);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("add dev to periodic adv list failed (%d)\n", rc);
+        /* TODO: destroy sink */
+        return rc;
+    }
+
+    (void)pa_sync_create();
+
+    return rc;
+}
+
+static int
+pa_sync_remove(const ble_addr_t *addr, uint8_t adv_sid)
+{
+    int rc;
+
+    if (periodic_adv_sync_in_progress) {
+        rc = pa_sync_create_cancel();
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    rc = ble_gap_rem_dev_from_periodic_adv_list(addr, adv_sid);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("rem dev from periodic adv list failed (%d)\n", rc);
+    }
+
+    return rc;
+}
+
+static void
+periodic_sync_handler(const ble_addr_t *addr, uint8_t adv_sid, uint8_t status, 
uint16_t pa_sync_handle)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    periodic_adv_sync_in_progress = false;
+
+    sink = broadcast_sink_lookup_addr_adv_sid_pair(addr, adv_sid);
+    if (sink == NULL) {
+        BLE_HS_LOG_DEBUG("sink not found\n");
+    } else {
+        (void)pa_sync_remove(addr, adv_sid);
+
+        if (status == BLE_ERR_SUCCESS) {
+            sink->pa_sync_handle = pa_sync_handle;
+            pa_sync_state_set(sink, PA_SYNC_STATE_ACTIVE);
+        } else if (status == BLE_ERR_OPERATION_CANCELLED) {
+            pa_sync_state_set(sink, PA_SYNC_STATE_IDLE);
+        } else if (status == BLE_ERR_CONN_ESTABLISHMENT) {
+            pa_sync_state_set(sink, PA_SYNC_STATE_TIMEOUT);
+        } else {
+            pa_sync_state_set(sink, PA_SYNC_STATE_ERROR);
+        }
+    }
+
+    sink = broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_SYNC);
+    if (sink != NULL) {
+        pa_sync_create();
+        disc_start();
+    } else {
+        disc_stop();
+    }
+}
+
+static void
+periodic_sync_lost_handler(uint16_t sync_handle, int reason)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    sink = broadcast_lookup_pa_sync_handle(sync_handle);
+    if (sink == NULL) {
+        BLE_HS_LOG_DEBUG("Unknown sync_handle %u\n", sync_handle);
+        return;
+    }
+
+    if (reason == BLE_HS_EDONE) {
+        pa_sync_state_set(sink, PA_SYNC_STATE_IDLE);
+    } else if (reason == BLE_HS_ETIMEOUT) {
+        pa_sync_state_set(sink, PA_SYNC_STATE_TIMEOUT);
+    } else {
+        pa_sync_state_set(sink, PA_SYNC_STATE_ERROR);
+    }
+}
+
+static void
+biginfo_report_handler(uint16_t pa_sync_handle, uint16_t iso_interval, uint8_t 
nse, uint8_t bn, uint8_t encryption)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    sink = broadcast_lookup_pa_sync_handle(pa_sync_handle);
+    if (sink == NULL) {
+        BLE_HS_LOG_DEBUG("Unknown pa_sync_handle %u\n", pa_sync_handle);
+        return;
+    }
+
+    if (sink->big_sync_state == BIG_SYNC_STATE_PENDING_BIG_INFO) {
+        sink->is_encrypted = encryption;
+        sink->iso_interval = iso_interval;
+        sink->nse = nse;
+        sink->bn = bn;
+
+        if (sink->is_encrypted && !sink->broadcast_code_is_valid) {
+            big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_CODE);
+        } else {
+            big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BASE);
+        }
+    }
+}
+
+static int
+bis_params_get(struct ble_audio_broadcast_sink *sink, struct 
ble_audio_base_group *group,
+               struct ble_audio_base_iter *subgroup_iter,
+               struct ble_iso_bis_params 
bis_params[MYNEWT_VAL(BLE_ISO_MAX_BISES)], uint8_t *out_bis_cnt)
+{
+    uint8_t subgroup_index;
+    uint32_t group_bis_sync = 0;
+    uint8_t bis_cnt = 0;
+    int rc = 0;
+
+    if (action_cb.fn == NULL) {
+        BLE_HS_LOG_ERROR("action_cb.fn is NULL\n");
+        return BLE_HS_EAPP;
+    }
+
+    for (subgroup_index = 0; subgroup_index < group->num_subgroups; 
subgroup_index++) {
+        struct ble_audio_base_subgroup subgroup;
+        struct ble_audio_base_iter bis_iter;
+        uint32_t subgroup_bis_sync_req;
+
+        rc = ble_audio_base_subgroup_iter(subgroup_iter, &subgroup, &bis_iter);
+        if (rc != 0) {
+            break;
+        }
+
+        subgroup_bis_sync_req = subgroup_bis_sync_get(sink, subgroup_index);
+        if (subgroup_bis_sync_req == 0) {
+            /* No BISes requested for this subgroup */
+            continue;
+        }
+
+        sink->subgroups[subgroup_index].bis_sync = 0;
+
+        for (uint8_t i = 0; i < subgroup.num_bis && bis_cnt < 
MYNEWT_VAL(BLE_ISO_MAX_BISES); i++) {
+            struct ble_audio_broadcast_sink_action action = {0};
+            struct ble_audio_base_bis bis;
+
+            rc = ble_audio_base_bis_iter(&bis_iter, &bis);
+            if (rc != 0) {
+                break;
+            }
+
+            /* Core 5.4 | Vol 4, Part E; 7.8.106 LE BIG Create Sync command
+             * BIS[i]: 0x01 to 0x1F
+             */
+            if (bis.index < 0x01 || bis.index > 0x7F) {
+                continue;
+            }
+
+            if (BIS_INDEX_TEST(group_bis_sync, bis.index)) {
+                /* BAP_v1.0.1; 3.7.2.2 Basic Audio Announcements
+                 *
+                 * Rule 3: Every BIS in the BIG, denoted by its BIS_index 
value,
+                 * shall only be present in one subgroup.
+                 */
+                BLE_HS_LOG_WARN("duplicated bis index 0x%02x", bis.index);
+                continue;
+            }
+
+            if (!BIS_INDEX_TEST(subgroup_bis_sync_req, bis.index)) {
+                continue;
+            }
+
+            action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_BIS_SYNC;
+            action.bis_sync.source_id = sink->source_id;
+            action.bis_sync.subgroup_index = subgroup_index;
+            action.bis_sync.bis = &bis;
+            action.bis_sync.subgroup = &subgroup;
+
+            rc = action_cb.fn(&action, action_cb.arg);
+            if (rc != 0) {
+                BLE_HS_LOG_WARN("bis sync rejected by user (%d)\n", rc);
+            } else {
+                BIS_INDEX_SET(sink->subgroups[subgroup_index].bis_sync, 
bis.index);
+                bis_params[bis_cnt].bis_index = bis.index;
+                bis_cnt++;
+            }
+        }
+
+        group_bis_sync |= sink->subgroups[subgroup_index].bis_sync;
+    }
+
+    sink->num_subgroups = subgroup_index;
+
+    *out_bis_cnt = bis_cnt;
+    return rc;
+}
+
+static int
+bis_params_bis_index_cmp(const void *p1, const void *p2)
+{
+    const struct ble_iso_bis_params *bis_params_1 = p1;
+    const struct ble_iso_bis_params *bis_params_2 = p2;
+
+    return bis_params_1->bis_index - bis_params_2->bis_index;
+}
+
+static void
+big_sync(struct ble_audio_broadcast_sink *sink, const uint8_t *base, uint8_t 
base_len)
+{
+    struct ble_audio_broadcast_sink_action action;
+    struct ble_audio_base_group group;
+    struct ble_audio_base_iter subgroup_iter;
+    struct ble_iso_big_sync_create_params big_sync_create_params;
+    struct ble_iso_bis_params bis_params[MYNEWT_VAL(BLE_ISO_MAX_BISES)];
+    char broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE + 1];
+    uint8_t bis_cnt = 0;
+    int rc;
+
+    rc = ble_audio_base_parse(base, base_len, &group, &subgroup_iter);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("base parse failed (%d)\n", rc);
+        ble_audio_broadcast_sink_stop(sink->source_id);
+        return;
+    }
+
+    /* By default, the controller can schedule reception of any number of 
subevents up to NSE */
+    big_sync_create_params.mse = 0x00;
+
+    /* By default, (6 * ISO_Interval * 1.25) / 10 = 3/4 * ISO_Interval */
+    big_sync_create_params.sync_timeout = (uint16_t)((3.0 * 
sink->iso_interval) / 4.0);
+    big_sync_create_params.sync_timeout = 
CLAMP(big_sync_create_params.sync_timeout, 0x000A, 0x4000);
+
+    action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_BIG_SYNC;
+    action.big_sync.source_id = sink->source_id;
+    action.big_sync.iso_interval = sink->iso_interval;
+    action.big_sync.nse = sink->nse;
+    action.big_sync.bn = sink->bn;
+    action.big_sync.presentation_delay = group.presentation_delay;
+    action.big_sync.out_mse = &big_sync_create_params.mse;
+    action.big_sync.out_sync_timeout = &big_sync_create_params.sync_timeout;
+
+    if (action_cb.fn == NULL) {
+        BLE_HS_LOG_ERROR("action_cb.fn is NULL\n");
+        ble_audio_broadcast_sink_stop(sink->source_id);
+        return;
+    }
+
+    rc = action_cb.fn(&action, action_cb.arg);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("big sync rejected by user (%d)\n", rc);
+        ble_audio_broadcast_sink_stop(sink->source_id);
+        return;
+    }
+
+    if (sink->broadcast_code_is_valid) {
+        memcpy(broadcast_code, sink->broadcast_code, 
BLE_AUDIO_BROADCAST_CODE_SIZE);
+        broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE] = '\0';
+        big_sync_create_params.broadcast_code = broadcast_code;
+    } else {
+        big_sync_create_params.broadcast_code = NULL;
+    }
+
+    big_sync_create_params.sync_handle = sink->pa_sync_handle;
+    big_sync_create_params.cb = iso_event_handler;
+    big_sync_create_params.cb_arg = UINT_TO_POINTER(sink->source_id);
+    big_sync_create_params.bis_params = bis_params;
+
+    rc = bis_params_get(sink, &group, &subgroup_iter, bis_params, &bis_cnt);
+    if (rc != 0 || bis_cnt == 0) {
+        ble_audio_broadcast_sink_stop(sink->source_id);
+        return;
+    }
+
+    /* Sort the parameters by BIS index in ascending order. It is required to 
properly match the
+     * BIS index with conn handle in BIG Sync Established event handler.
+     */
+    qsort(bis_params, bis_cnt, sizeof(*bis_params), bis_params_bis_index_cmp);
+
+    big_sync_create_params.bis_cnt = bis_cnt;
+
+    /* Stop scan first */
+    disc_stop();
+
+    rc = ble_iso_big_sync_create(&big_sync_create_params, &sink->big_handle);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("big sync failed (%d)\n", rc);
+        return;
+    }
+
+    big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_SYNC);
+}
+
+static void
+metadata_update(struct ble_audio_broadcast_sink *sink, const uint8_t *base, 
uint8_t base_len)
+{
+    struct ble_audio_event event;
+    struct ble_audio_base_group group;
+    struct ble_audio_base_iter subgroup_iter;
+    int rc = 0;
+
+    rc = ble_audio_base_parse(base, base_len, &group, &subgroup_iter);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("base parse failed (%d)\n", rc);
+        return;
+    }
+
+    for (uint8_t subgroup_index = 0; subgroup_index < group.num_subgroups; 
subgroup_index++) {
+        struct ble_audio_base_subgroup subgroup;
+        uint32_t bis_sync_state;
+
+        rc = ble_audio_base_subgroup_iter(&subgroup_iter, &subgroup, NULL);
+        if (rc != 0) {
+            break;
+        }
+
+        bis_sync_state = subgroup_bis_sync_get(sink, subgroup_index);
+        if (bis_sync_state == 0) {
+            /* No BISes synced for this subgroup */
+            continue;
+        }
+
+        event.type = BLE_AUDIO_EVENT_BROADCAST_SINK_METADATA;
+        event.broadcast_sink_metadata.source_id = sink->source_id;
+        event.broadcast_sink_metadata.bis_sync = bis_sync_state;
+        event.broadcast_sink_metadata.metadata = subgroup.metadata;
+        event.broadcast_sink_metadata.metadata_length = subgroup.metadata_len;
+
+        /* TODO: filter duplicates */
+
+        ble_audio_event_listener_call(&event);
+    }
+}
+
+static void
+periodic_report_handler(uint16_t pa_sync_handle, const uint8_t *data, uint8_t 
data_length, uint8_t data_status,
+                        int8_t rssi, int8_t tx_power)
+{
+    struct ble_audio_broadcast_sink *sink;
+    struct periodic_report report = {0};
+    int rc;
+
+    if (data_status != BLE_HCI_PERIODIC_DATA_STATUS_COMPLETE) {
+        return;
+    }
+
+    sink = broadcast_lookup_pa_sync_handle(pa_sync_handle);
+    if (sink == NULL) {
+        BLE_HS_LOG_DEBUG("Unknown pa_sync_handle %u\n", pa_sync_handle);
+        return;
+    }
+
+    if (sink->big_sync_state == BIG_SYNC_STATE_PENDING_BASE) {
+        rc = ble_hs_adv_parse(data, data_length, periodic_report_parse, 
&report);
+        if (rc != 0 || report.uuid16.basic_audio_announcement.length == 0) {
+            BLE_HS_LOG_WARN("source_id %u incorrectly formatted BASE\n", 
sink->source_id);
+            ble_audio_broadcast_sink_stop(sink->source_id);
+            return;
+        }
+
+        big_sync(sink, report.uuid16.basic_audio_announcement.base, 
report.uuid16.basic_audio_announcement.length);
+    } else if (sink->big_sync_state == BIG_SYNC_STATE_ACTIVE) {
+        rc = ble_hs_adv_parse(data, data_length, periodic_report_parse, 
&report);
+        if (rc != 0 || report.uuid16.basic_audio_announcement.length == 0) {
+            BLE_HS_LOG_WARN("source_id %u incorrectly formatted BASE\n", 
sink->source_id);
+            return;
+        }
+
+        metadata_update(sink, report.uuid16.basic_audio_announcement.base,
+                        report.uuid16.basic_audio_announcement.length);
+    }
+}
+
+static int
+broadcast_id_parse_from_adv(const struct ble_hs_adv_field *field, void 
*user_data)
+{
+    const uint8_t value_len = field->length - sizeof(field->length);
+    uint32_t *broadcast_id = user_data;
+
+    if (field->type == BLE_HS_ADV_TYPE_SVC_DATA_UUID16) {
+        ble_uuid16_t uuid16 = BLE_UUID16_INIT(0);
+        uint8_t offset = 0;
+
+        if (value_len < 2) {
+            /* Continue parsing */
+            return BLE_HS_ENOENT;
+        }
+
+        uuid16.value = get_le16(&field->value[offset]);
+        offset += 2;
+
+        if (uuid16.value == BLE_BROADCAST_AUDIO_ANNOUNCEMENT_SVC_UUID) {
+            if ((value_len - offset) >= 3) {
+                *broadcast_id = get_le24(&field->value[offset]);
+            }
+
+            /* stop parsing */
+            return 0;
+        }
+    }
+
+    /* continue parsing */
+    return BLE_HS_ENOENT;
+}
+
+static void
+ext_disc_handler(const ble_addr_t *addr, uint8_t adv_sid, const uint8_t *data, 
uint8_t data_length)
+{
+    uint32_t broadcast_id = BROADCAST_ID_INVALID;
+    struct ble_audio_broadcast_sink *sink;
+    int rc;
+
+    if (broadcast_sink_lookup_pa_sync_state(PA_SYNC_STATE_PENDING_DISC) == 
NULL) {
+        return;
+    }
+
+    rc = ble_hs_adv_parse(data, data_length, broadcast_id_parse_from_adv, 
&broadcast_id);
+    if (rc != 0 || broadcast_id == BROADCAST_ID_INVALID) {
+        return;
+    }
+
+    sink = broadcast_sink_lookup_adv_sid_broadcast_id_pair(adv_sid, 
broadcast_id);
+    if (sink == NULL) {
+        return;
+    }
+
+    if (sink->pa_sync_state == PA_SYNC_STATE_PENDING_DISC) {
+        rc = pa_sync_add(addr, adv_sid);
+        if (rc != 0) {
+            /* TODO: */
+        } else {
+            pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_SYNC);
+        }
+    }
+}
+
+static int
+gap_event_handler(struct ble_gap_event *event, void *arg)
+{
+    switch (event->type) {
+    case BLE_GAP_EVENT_PERIODIC_SYNC:
+        periodic_sync_handler(&event->periodic_sync.adv_addr, 
event->periodic_sync.sid,
+                              event->periodic_sync.status, 
event->periodic_sync.sync_handle);
+        break;
+
+    case BLE_GAP_EVENT_PERIODIC_SYNC_LOST:
+        periodic_sync_lost_handler(event->periodic_sync_lost.sync_handle, 
event->periodic_sync_lost.reason);
+        break;
+
+    case BLE_GAP_EVENT_PERIODIC_TRANSFER:
+        periodic_sync_handler(&event->periodic_transfer.adv_addr, 
event->periodic_transfer.sid,
+                              event->periodic_transfer.status, 
event->periodic_transfer.sync_handle);
+        break;
+
+    case BLE_GAP_EVENT_BIGINFO_REPORT:
+        biginfo_report_handler(event->biginfo_report.sync_handle, 
event->biginfo_report.iso_interval,
+                               event->biginfo_report.nse, 
event->biginfo_report.bn, event->biginfo_report.encryption);
+
+        break;
+
+    case BLE_GAP_EVENT_PERIODIC_REPORT:
+        periodic_report_handler(event->periodic_report.sync_handle, 
event->periodic_report.data,
+                                event->periodic_report.data_length,
+                                event->periodic_report.data_status, 
event->periodic_report.rssi,
+                                event->periodic_report.tx_power);
+        break;
+
+    case BLE_GAP_EVENT_EXT_DISC:
+        ext_disc_handler(&event->ext_disc.addr, event->ext_disc.sid, 
event->ext_disc.data,
+                         event->ext_disc.length_data);
+        break;
+
+    default:
+        break;
+    }
+
+    return 0;
+}
+
+int
+ble_audio_broadcast_sink_cb_set(ble_audio_broadcast_sink_action_fn *cb, void 
*arg)
+{
+    if (action_cb.fn != NULL) {
+        return BLE_HS_EALREADY;
+    }
+
+    action_cb.fn = cb;
+    action_cb.arg = arg;
+
+    return 0;
+}
+
+void
+ble_audio_broadcast_sink_code_set(uint8_t source_id, const uint8_t 
broadcast_code[BLE_AUDIO_BROADCAST_CODE_SIZE])
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    BLE_AUDIO_DBG_ASSERT(broadcast_code != NULL);
+
+    sink = broadcast_sink_get(source_id);
+    if (sink == NULL) {
+        BLE_HS_LOG_DEBUG("Unknown source_id %u\n", source_id);
+        return;
+    }
+
+    if (sink->big_sync_state == BIG_SYNC_STATE_PENDING_CODE) {
+        memcpy(sink->broadcast_code, broadcast_code, 
BLE_AUDIO_BROADCAST_CODE_SIZE);
+
+        big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BASE);
+    }
+}
+
+static struct ble_audio_broadcast_sink *
+broadcast_sink_new(uint8_t source_id)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    sink = os_memblock_get(&ble_audio_broadcast_sink_pool);
+    if (sink == NULL) {
+        BLE_HS_LOG_WARN("Out of memory\n");
+        return NULL;
+    }
+
+    memset(sink, 0, sizeof(*sink));
+
+    sink->source_id = source_id;
+
+    SLIST_INSERT_HEAD(&ble_audio_broadcast_sink_list, sink, next);
+
+    return sink;
+}
+
+static int
+pa_sync_receive(struct ble_audio_broadcast_sink *sink, const uint16_t 
*conn_handle)
+{
+    struct ble_audio_broadcast_sink_action action;
+    struct ble_audio_scan_delegator_source_desc source_desc;
+    struct ble_gap_periodic_sync_params periodic_sync_params = {0};
+    int rc;
+
+    rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, 
&source_desc);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc);
+        return rc;
+    }
+
+    if (action_cb.fn == NULL) {
+        BLE_HS_LOG_ERROR("action_cb.fn is NULL\n");
+        return BLE_HS_EAPP;
+    }
+
+    action.type = BLE_AUDIO_BROADCAST_SINK_ACTION_PA_SYNC;
+    action.pa_sync.out_params = &periodic_sync_params;
+
+    rc = action_cb.fn(&action, action_cb.arg);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("pa sync rejected by user (%d)\n", rc);
+        return rc;
+    }
+
+    rc = ble_gap_periodic_adv_sync_receive(
+            *conn_handle, &periodic_sync_params, gap_event_handler, NULL);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("sync receive failed (%d)\n", rc);
+        return rc;
+    }
+
+    return 0;
+}
+
+static int
+broadcast_sink_start(uint8_t source_id, const uint8_t *broadcast_code, 
uint16_t *conn_handle)
+{
+    struct ble_audio_scan_delegator_source_desc source_desc;
+    struct ble_audio_broadcast_sink *sink;
+    int rc;
+
+    rc = ble_audio_scan_delegator_source_desc_get(source_id, &source_desc);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc);
+        return rc;
+    }
+
+    sink = broadcast_sink_get(source_id);
+    if (sink == NULL) {
+        sink = broadcast_sink_new(source_id);
+        if (sink == NULL) {
+            return BLE_HS_ENOMEM;
+        }
+    }
+
+    if (broadcast_code != NULL) {
+        memcpy(sink->broadcast_code, broadcast_code, 
BLE_AUDIO_BROADCAST_CODE_SIZE);
+        sink->broadcast_code_is_valid = true;
+    }
+
+    /* If not previously set, let the application decide which BISes to sync */
+    if (sink->num_subgroups == 0) {
+        sink->num_subgroups = ARRAY_SIZE(sink->subgroups);
+        for (uint8_t i = 0; i < sink->num_subgroups; i++) {
+            sink->subgroups[i].bis_sync = 
BLE_AUDIO_SCAN_DELEGATOR_BIS_SYNC_ANY;
+        }
+    }
+
+    switch (sink->pa_sync_state) {
+    case PA_SYNC_STATE_PENDING_PAST:
+    case PA_SYNC_STATE_PENDING_DISC:
+    case PA_SYNC_STATE_PENDING_SYNC:
+    case PA_SYNC_STATE_ACTIVE:
+        break;
+
+    case PA_SYNC_STATE_IDLE:
+    case PA_SYNC_STATE_ERROR:
+    case PA_SYNC_STATE_TIMEOUT:
+        if (conn_handle != NULL) {
+            /* sync using PAST procedure */
+            rc = pa_sync_receive(sink, conn_handle);
+            if (rc != 0) {
+                return rc;
+            }
+            pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_PAST);
+        } else if (source_desc.addr.type == BLE_ADDR_PUBLIC) {
+            /* sync to public address (we don't need to scan, as the address 
won't change) */
+            rc = pa_sync_add(&source_desc.addr, source_desc.adv_sid);
+            if (rc != 0) {
+                return rc;
+            }
+            pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_SYNC);
+        } else {
+            /* scan to find broadcaster using Adv SID and Broadcast ID */
+            rc = disc_start();
+            if (rc != 0) {
+                return rc;
+            }
+            pa_sync_state_set(sink, PA_SYNC_STATE_PENDING_DISC);
+        }
+        break;
+
+    default:
+        BLE_AUDIO_DBG_ASSERT(false);
+        ble_audio_broadcast_sink_stop(source_id);
+        return BLE_HS_EAGAIN;
+    }
+
+    switch (sink->big_sync_state) {
+    case BIG_SYNC_STATE_ACTIVE:
+    case BIG_SYNC_STATE_PENDING_BIG_INFO:
+    case BIG_SYNC_STATE_PENDING_SYNC:
+    case BIG_SYNC_STATE_PENDING_BASE:
+        break;
+
+    case BIG_SYNC_STATE_PENDING_CODE:
+        if (broadcast_code != NULL) {
+            big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BASE);
+        }
+        break;
+
+    case BIG_SYNC_STATE_FAILED:
+    case BIG_SYNC_STATE_IDLE:
+        big_sync_state_set(sink, BIG_SYNC_STATE_PENDING_BIG_INFO);
+        break;
+
+    default:
+        BLE_AUDIO_DBG_ASSERT(false);
+        ble_audio_broadcast_sink_stop(source_id);
+        return BLE_HS_EAGAIN;
+    }
+
+    if (sink->pa_sync_state == PA_SYNC_STATE_ACTIVE &&
+        sink->big_sync_state == BIG_SYNC_STATE_ACTIVE) {
+        return BLE_HS_EDONE;
+    }
+
+    return 0;
+}
+
+int
+ble_audio_broadcast_sink_start(uint8_t source_id, const struct 
ble_audio_broadcast_sink_add_params *params)
+{
+    return broadcast_sink_start(source_id,
+                                params->broadcast_code_is_valid ? 
params->broadcast_code : NULL,
+                                NULL);
+}
+
+static void
+ble_audio_broadcast_sink_destroy(struct ble_audio_broadcast_sink *sink)
+{
+    os_error_t os_error;
+
+    os_error = os_memblock_put(&ble_audio_broadcast_sink_pool, sink);
+    if (os_error != OS_OK) {
+        BLE_HS_LOG_ERROR("Failed to put memory block (os_error %d)\n", 
os_error);
+        return;
+    }
+
+    SLIST_REMOVE(&ble_audio_broadcast_sink_list, sink, 
ble_audio_broadcast_sink, next);
+}
+
+static int
+pa_sync_term(struct ble_audio_broadcast_sink *sink)
+{
+    int rc;
+
+    switch (sink->pa_sync_state) {
+    case PA_SYNC_STATE_ACTIVE:
+        rc = ble_gap_periodic_adv_sync_terminate(sink->pa_sync_handle);
+        if (rc != 0) {
+            BLE_HS_LOG_ERROR("adv sync terminate failed (%d)\n", rc);
+            return rc;
+        }
+        break;
+
+    case PA_SYNC_STATE_PENDING_PAST:
+        rc = ble_gap_periodic_adv_sync_receive(sink->past_conn_handle, NULL, 
gap_event_handler, NULL);
+        if (rc != 0) {
+            BLE_HS_LOG_ERROR("adv sync receive cancel failed (%d)\n", rc);
+            return rc;
+        }
+        break;
+
+    case PA_SYNC_STATE_PENDING_SYNC: {
+        struct ble_audio_scan_delegator_source_desc source_desc;
+
+        rc = ble_audio_scan_delegator_source_desc_get(sink->source_id, 
&source_desc);
+        if (rc != 0) {
+            BLE_HS_LOG_ERROR("source desc get failed (%d)\n", rc);
+            return rc;
+        }
+
+        rc = pa_sync_remove(&source_desc.addr, source_desc.adv_sid);
+        if (rc != 0) {
+            return rc;
+        }
+        break;
+    }
+
+    default:
+        break;
+    }
+
+    pa_sync_state_set(sink, PA_SYNC_STATE_IDLE);
+
+    return 0;
+}
+
+static int
+big_sync_term(struct ble_audio_broadcast_sink *sink)
+{
+    int rc;
+
+    switch (sink->big_sync_state) {
+    case BIG_SYNC_STATE_ACTIVE:
+    case BIG_SYNC_STATE_PENDING_SYNC:
+        rc = ble_iso_big_sync_terminate(sink->big_handle);
+        if (rc != 0) {
+            BLE_HS_LOG_ERROR("big sync terminate failed (%d)\n", rc);
+            return rc;
+        }
+        break;
+
+    case BIG_SYNC_STATE_IDLE:
+    case BIG_SYNC_STATE_FAILED:
+    case BIG_SYNC_STATE_PENDING_CODE:
+    case BIG_SYNC_STATE_PENDING_BASE:
+    case BIG_SYNC_STATE_PENDING_BIG_INFO:
+        break;
+    }
+
+    big_sync_state_set(sink, BIG_SYNC_STATE_IDLE);
+
+    return 0;
+}
+
+int
+ble_audio_broadcast_sink_stop(uint8_t source_id)
+{
+    struct ble_audio_broadcast_sink *sink;
+    int rc;
+
+    sink = broadcast_sink_get(source_id);
+    if (sink == NULL) {
+        BLE_HS_LOG_WARN("no sink with source_id=0x%02x\n", source_id);
+        return 0;
+    }
+
+    rc = pa_sync_term(sink);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = big_sync_term(sink);
+    if (rc != 0) {
+        return rc;
+    }
+
+    ble_audio_broadcast_sink_destroy(sink);
+
+    return 0;
+}
+
+int
+ble_audio_broadcast_sink_metadata_update(uint8_t source_id,
+                                         const struct 
ble_audio_broadcast_sink_metadata_update_params *params)
+{
+    struct ble_audio_broadcast_sink *sink;
+
+    sink = broadcast_sink_get(source_id);
+    if (sink == NULL) {
+        BLE_HS_LOG_WARN("no sink with source_id=0x%02x\n", source_id);
+        return 0;
+    }
+
+    return ble_audio_scan_delegator_metadata_update(sink->source_id, 
params->subgroup_index, params->metadata,
+                                                    params->metadata_length);
+}
+
+int
+ble_audio_broadcast_sink_config(uint8_t source_id, uint16_t conn_handle,
+                                const struct ble_audio_scan_delegator_sync_opt 
*sync_opt)
+{
+    struct ble_audio_broadcast_sink *sink;
+    int rc;
+
+    BLE_AUDIO_DBG_ASSERT(sync_opt != NULL);
+
+    sink = broadcast_sink_get(source_id);
+    if (sink == NULL) {
+        if (sync_opt->pa_sync != BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_DO_NOT_SYNC) 
{
+            sink = broadcast_sink_new(source_id);
+            if (sink == NULL) {
+                return BLE_HS_ENOMEM;
+            }
+        } else {
+            /* nothing to do */
+            return 0;
+        }
+    }
+
+    if (sync_opt->pa_sync != BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_DO_NOT_SYNC) {
+        /* TODO: Skip if the BIS Sync is same */
+        if (sink->num_subgroups != 0) {
+            rc = big_sync_term(sink);
+            if (rc != 0) {
+                return rc;
+            }
+        }
+
+        sink->num_subgroups = sync_opt->num_subgroups;
+
+        for (uint8_t subgroup_index = 0; subgroup_index < sink->num_subgroups; 
subgroup_index++) {
+            sink->subgroups[subgroup_index].bis_sync = 
sync_opt->subgroups[subgroup_index].bis_sync;
+        }
+
+        if (sync_opt->pa_sync == 
BLE_AUDIO_SCAN_DELEGATOR_PA_SYNC_PAST_NOT_AVAILABLE) {
+            rc = broadcast_sink_start(source_id, NULL, NULL);
+        } else {
+            rc = broadcast_sink_start(source_id, NULL, &conn_handle);
+        }
+    } else {
+        rc = pa_sync_term(sink);
+    }
+
+    return rc;
+}
+
+int
+ble_audio_broadcast_sink_init(void)
+{
+    static struct ble_gap_event_listener gap_event_listener;
+    int rc;
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+    rc = os_mempool_init(&ble_audio_broadcast_sink_pool,
+                         MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_MAX),
+                         sizeof(struct ble_audio_broadcast_sink),
+                         ble_audio_broadcast_sink_mem,
+                         "ble_audio_broadcast_sink_pool");
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    rc = ble_gap_event_listener_register(&gap_event_listener, 
gap_event_handler, NULL);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+
+    return 0;
+}
+#endif /* BLE_AUDIO_BROADCAST_SINK */
diff --git a/nimble/host/audio/src/ble_audio_priv.h 
b/nimble/host/audio/src/ble_audio_broadcast_sink_priv.h
similarity index 63%
copy from nimble/host/audio/src/ble_audio_priv.h
copy to nimble/host/audio/src/ble_audio_broadcast_sink_priv.h
index 10f0109d..ad799014 100644
--- a/nimble/host/audio/src/ble_audio_priv.h
+++ b/nimble/host/audio/src/ble_audio_broadcast_sink_priv.h
@@ -17,11 +17,18 @@
  * under the License.
  */
 
-#ifndef H_BLE_AUDIO_PRIV_
-#define H_BLE_AUDIO_PRIV_
+#ifndef H_BLE_AUDIO_BROADCAST_SINK_PRIV_
+#define H_BLE_AUDIO_BROADCAST_SINK_PRIV_
 
+#include <stdint.h>
 #include "audio/ble_audio.h"
+#include "audio/ble_audio_broadcast_sink.h"
+#include "audio/ble_audio_scan_delegator.h"
 
-int ble_audio_event_listener_call(struct ble_audio_event *event);
+int ble_audio_broadcast_sink_config(
+        uint8_t source_id, uint16_t conn_handle,
+        const struct ble_audio_scan_delegator_sync_opt *sync_opt);
+void ble_audio_broadcast_sink_code_set(
+        uint8_t source_id, const uint8_t broadcast_code[16]);
 
-#endif /* H_BLE_AUDIO_PRIV_ */
+#endif /* H_BLE_AUDIO_BROADCAST_SINK_PRIV_ */
diff --git a/nimble/host/audio/src/ble_audio_priv.h 
b/nimble/host/audio/src/ble_audio_priv.h
index 10f0109d..d575c549 100644
--- a/nimble/host/audio/src/ble_audio_priv.h
+++ b/nimble/host/audio/src/ble_audio_priv.h
@@ -22,6 +22,17 @@
 
 #include "audio/ble_audio.h"
 
+#define MIN(_a, _b) ((_a) < (_b) ? (_a) : (_b))
+#define MAX(_a, _b) ((_a) > (_b) ? (_a) : (_b))
+
+#if MYNEWT_VAL(BLE_HS_DEBUG)
+#define BLE_AUDIO_DBG_ASSERT(x) assert(x)
+#define BLE_AUDIO_DBG_ASSERT_EVAL(x) assert(x)
+#else
+#define BLE_AUDIO_DBG_ASSERT(x)
+#define BLE_AUDIO_DBG_ASSERT_EVAL(x) ((void)(x))
+#endif
+
 int ble_audio_event_listener_call(struct ble_audio_event *event);
 
 #endif /* H_BLE_AUDIO_PRIV_ */
diff --git a/nimble/host/audio/src/ble_audio_scan_delegator.c 
b/nimble/host/audio/src/ble_audio_scan_delegator.c
new file mode 100644
index 00000000..db580c63
--- /dev/null
+++ b/nimble/host/audio/src/ble_audio_scan_delegator.c
@@ -0,0 +1,460 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include "sysinit/sysinit.h"
+
+#if MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR)
+#include "audio/ble_audio.h"
+#include "audio/ble_audio_broadcast_sink.h"
+#include "audio/ble_audio_scan_delegator.h"
+#include "host/ble_hs.h"
+#include "host/ble_uuid.h"
+
+#include "../services/bass/include/services/bass/ble_audio_svc_bass.h"
+
+#include "ble_audio_priv.h"
+#include "ble_audio_broadcast_sink_priv.h"
+
+static ble_audio_scan_delegator_action_fn *action_cb;
+
+int
+ble_audio_scan_delegator_source_desc_get(uint8_t source_id, struct 
ble_audio_scan_delegator_source_desc *source_desc)
+{
+    struct ble_svc_audio_bass_receiver_state *state;
+    int rc;
+
+    rc = ble_svc_audio_bass_receiver_state_get(source_id, &state);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("bass receiver state get failed (%d)\n", rc);
+        return rc;
+    }
+
+    source_desc->addr = state->source_addr;
+    source_desc->adv_sid = state->source_adv_sid;
+    source_desc->broadcast_id = state->broadcast_id;
+
+    return 0;
+}
+
+int
+ble_audio_scan_delegator_receive_state_get(uint8_t source_id, struct 
ble_audio_scan_delegator_receive_state *out_state)
+{
+    struct ble_svc_audio_bass_receiver_state *state;
+    int rc;
+
+    rc = ble_svc_audio_bass_receiver_state_get(source_id, &state);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("bass receiver state get failed (%d)\n", rc);
+        return rc;
+    }
+
+    out_state->pa_sync_state = (uint8_t)state->pa_sync_state;
+    out_state->big_enc = (uint8_t)state->big_encryption;
+    if (out_state->big_enc == 
BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) {
+        memcpy(out_state->bad_code, state->bad_code, 
sizeof(out_state->bad_code));
+    }
+    out_state->num_subgroups = state->num_subgroups;
+    for (uint8_t i = 0; i < out_state->num_subgroups; i++) {
+        out_state->subgroups[i].bis_sync = state->subgroups[i].bis_sync_state;
+        out_state->subgroups[i].metadata = state->subgroups[i].metadata;
+        out_state->subgroups[i].metadata_length = 
state->subgroups[i].metadata_length;
+    }
+
+    return 0;
+}
+
+int
+ble_audio_scan_delegator_metadata_update(uint8_t source_id, uint8_t 
subgroup_index, const uint8_t *metadata,
+                                         uint8_t metadata_length)
+{
+    struct ble_svc_audio_bass_metadata_params params;
+
+    params.subgroup_idx = subgroup_index;
+    params.metadata = metadata;
+    params.metadata_length = metadata_length;
+
+    return ble_svc_audio_bass_update_metadata(&params, source_id);
+}
+
+static int
+action_call(struct ble_audio_scan_delegator_action *action, void *arg)
+{
+    int rc;
+
+    if (action_cb == NULL) {
+        BLE_HS_LOG_ERROR("callback is NULL\n");
+        return BLE_HS_EAPP;
+    }
+
+    rc = action_cb(action, arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static void
+source_desc_init(struct ble_audio_scan_delegator_source_desc *source_desc, 
const ble_addr_t *addr, uint8_t adv_sid,
+                 uint32_t broadcast_id)
+{
+    source_desc->addr = *addr;
+    source_desc->adv_sid = adv_sid;
+    source_desc->broadcast_id = broadcast_id;
+}
+
+static void
+subgroups_init(struct ble_audio_scan_delegator_subgroup *subgroups,
+               const struct ble_svc_audio_bass_subgroup *bass_subgroups, 
uint8_t num_subgroups)
+{
+    BLE_AUDIO_DBG_ASSERT(num_subgroups < 
MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX));
+
+    for (uint8_t i = 0; i < num_subgroups; i++) {
+        subgroups[i].bis_sync = bass_subgroups[i].bis_sync_state;
+        subgroups[i].metadata_length = bass_subgroups[i].metadata_length;
+        subgroups[i].metadata = bass_subgroups[i].metadata;
+    }
+}
+
+static void
+sync_opt_init(struct ble_audio_scan_delegator_sync_opt *sync_opt, enum 
ble_svc_audio_bass_pa_sync pa_sync,
+              uint16_t pa_interval, const struct ble_svc_audio_bass_subgroup 
*bass_subgroups, uint8_t num_subgroups)
+{
+    sync_opt->pa_sync = (uint8_t)pa_sync;
+    sync_opt->pa_interval = pa_interval;
+    sync_opt->num_subgroups = num_subgroups;
+    if (sync_opt->num_subgroups > 0) {
+        subgroups_init(sync_opt->subgroups, bass_subgroups, num_subgroups);
+    }
+}
+
+static int
+bass_add_source_op_handler(struct ble_svc_audio_bass_operation *op, void *arg)
+{
+    struct ble_audio_scan_delegator_action action = {0};
+    const uint8_t source_id = op->add_source.source_id;
+    int rc;
+
+    source_desc_init(&action.source_add.source_desc, &op->add_source.adv_addr,
+                     op->add_source.adv_sid, op->add_source.broadcast_id);
+    sync_opt_init(&action.source_add.sync_opt, op->add_source.pa_sync, 
op->add_source.pa_interval,
+                  op->add_source.subgroups, op->add_source.num_subgroups);
+
+    action.type = BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_ADD;
+    action.source_add.source_id = source_id;
+    action.source_add.out_source_id_to_swap = 
op->add_source.out_source_id_to_swap;
+
+    rc = action_call(&action, arg);
+    if (rc != 0) {
+        BLE_HS_LOG_DEBUG("API callback (%d)\n", rc);
+        return rc;
+    }
+
+#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)
+    if (op->add_source.out_source_id_to_swap != NULL) {
+        rc = 
ble_audio_broadcast_sink_stop(*op->add_source.out_source_id_to_swap);
+        if (rc != 0) {
+            BLE_HS_LOG_WARN("sink stop failed (%d)\n", rc);
+        }
+    }
+
+    rc = ble_audio_broadcast_sink_config(source_id, op->conn_handle, 
&action.source_add.sync_opt);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("sink config failed (%d)\n", rc);
+    }
+#endif /* BLE_AUDIO_BROADCAST_SINK */
+
+    return 0;
+}
+
+static int
+bass_modify_source_op_handler(struct ble_svc_audio_bass_operation *op, void 
*arg)
+{
+    struct ble_audio_scan_delegator_action action = {0};
+    struct ble_audio_scan_delegator_sync_opt *sync_opt;
+    const uint8_t source_id = op->modify_source.source_id;
+    int rc;
+
+    sync_opt = &action.source_modify.sync_opt;
+    sync_opt_init(sync_opt, op->modify_source.pa_sync, 
op->modify_source.pa_interval, NULL, 0);
+
+    BLE_AUDIO_DBG_ASSERT(sync_opt->num_subgroups < ARRAY_SIZE(subgroups));
+
+    for (uint8_t i = 0; i < sync_opt->num_subgroups; i++) {
+        sync_opt->subgroups[i].bis_sync = op->modify_source.bis_sync[i];
+        /* FIXME: Missing metadata in Modify Source */
+    }
+
+    action.type = BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_MODIFY;
+    action.source_modify.source_id = source_id;
+
+    rc = action_call(&action, arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)
+    rc = ble_audio_broadcast_sink_config(source_id, op->conn_handle, sync_opt);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("sink config failed (%d)\n", rc);
+    }
+#endif /* BLE_AUDIO_BROADCAST_SINK */
+
+    return 0;
+}
+
+static int
+bass_remove_source_op_handler(struct ble_svc_audio_bass_operation *op, void 
*arg)
+{
+    struct ble_audio_scan_delegator_action action;
+    const uint8_t source_id = op->remove_source.source_id;
+    int rc;
+
+    action.type = BLE_AUDIO_SCAN_DELEGATOR_ACTION_SOURCE_REMOVE;
+    action.source_remove.source_id = source_id;
+
+    rc = action_call(&action, arg);
+    if (rc != 0) {
+        return rc;
+    }
+
+#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)
+    rc = ble_audio_broadcast_sink_stop(source_id);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("sink stop failed (%d)\n", rc);
+    }
+#endif /* BLE_AUDIO_BROADCAST_SINK */
+
+    return 0;
+}
+
+static int
+bass_accept_fn(struct ble_svc_audio_bass_operation *op, void *arg)
+{
+    switch (op->op) {
+    case BLE_SVC_AUDIO_BASS_OPERATION_ADD_SOURCE:
+        return bass_add_source_op_handler(op, arg);
+
+    case BLE_SVC_AUDIO_BASS_OPERATION_MODIFY_SOURCE:
+        return bass_modify_source_op_handler(op, arg);
+
+    case BLE_SVC_AUDIO_BASS_OPERATION_REMOVE_SOURCE:
+        return bass_remove_source_op_handler(op, arg);
+
+    default:
+        return BLE_HS_ENOTSUP;
+    }
+}
+
+int
+ble_audio_scan_delegator_action_fn_set(ble_audio_scan_delegator_action_fn *fn, 
void *arg)
+{
+    int rc;
+
+    if (fn == NULL) {
+        BLE_HS_LOG_ERROR("callback is NULL\n");
+        return BLE_HS_EINVAL;
+    }
+
+    if (action_cb != NULL) {
+        return BLE_HS_EALREADY;
+    }
+
+    action_cb = fn;
+
+    rc = ble_svc_audio_bass_accept_fn_set(bass_accept_fn, arg);
+    if (rc != 0) {
+        action_cb = NULL;
+    }
+
+    return 0;
+}
+
+int
+ble_audio_scan_delegator_receive_state_add(const struct 
ble_audio_scan_delegator_receive_state_add_params *params,
+                                           uint8_t *source_id)
+{
+    struct ble_svc_audio_bass_receiver_state_add_params bass_params = {0};
+
+    if (params == NULL) {
+        BLE_HS_LOG_ERROR("NULL params\n");
+        return BLE_HS_EINVAL;
+    }
+
+    if (source_id == NULL) {
+        BLE_HS_LOG_ERROR("NULL source_id\n");
+        return BLE_HS_EINVAL;
+    }
+
+    bass_params.source_addr = params->source_desc.addr;
+    bass_params.source_adv_sid = params->source_desc.adv_sid;
+    bass_params.broadcast_id = params->source_desc.broadcast_id;
+    bass_params.pa_sync_state = (uint8_t)params->state.pa_sync_state;
+    bass_params.big_encryption = (uint8_t)params->state.big_enc;
+
+    if (params->state.big_enc == 
BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) {
+        bass_params.bad_code = params->state.bad_code;
+    } else {
+        bass_params.bad_code = NULL;
+    }
+
+    bass_params.num_subgroups = params->state.num_subgroups;
+    if (bass_params.num_subgroups > BLE_SVC_AUDIO_BASS_SUB_NUM_MAX) {
+        BLE_HS_LOG_ERROR("num_subgroups above the limit\n");
+        return BLE_HS_ENOMEM;
+    }
+
+    for (uint8_t i = 0; i < bass_params.num_subgroups; i++) {
+        bass_params.subgroups[i].bis_sync_state = 
params->state.subgroups->bis_sync;
+        bass_params.subgroups[i].metadata_length = 
params->state.subgroups->metadata_length;
+        bass_params.subgroups[i].metadata = params->state.subgroups->metadata;
+    }
+
+    return ble_svc_audio_bass_receive_state_add(&bass_params, source_id);
+}
+
+int
+ble_audio_scan_delegator_receive_state_remove(uint8_t source_id)
+{
+    int rc;
+
+#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)
+    rc = ble_audio_broadcast_sink_stop(source_id);
+    if (rc != 0) {
+        BLE_HS_LOG_WARN("sink stop failed (%d)\n", rc);
+    }
+#endif /* BLE_AUDIO_BROADCAST_SINK */
+
+    return ble_svc_audio_bass_receive_state_remove(source_id);
+}
+
+int
+ble_audio_scan_delegator_receive_state_set(uint8_t source_id,
+                                           const struct 
ble_audio_scan_delegator_receive_state *state)
+{
+    struct ble_svc_audio_bass_update_params bass_params;
+    int rc;
+
+    if (state == NULL) {
+        BLE_HS_LOG_ERROR("NULL state\n");
+        return BLE_HS_EINVAL;
+    }
+
+    bass_params.pa_sync_state = (uint8_t)state->pa_sync_state;
+    bass_params.big_encryption = (uint8_t)state->big_enc;
+
+    if (state->big_enc == 
BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) {
+        bass_params.bad_code = state->bad_code;
+    } else {
+        bass_params.bad_code = NULL;
+    }
+
+    bass_params.num_subgroups = state->num_subgroups;
+    if (bass_params.num_subgroups > BLE_SVC_AUDIO_BASS_SUB_NUM_MAX) {
+        BLE_HS_LOG_ERROR("num_subgroups above the limit\n");
+        return BLE_HS_ENOMEM;
+    }
+
+    for (uint8_t i = 0; i < bass_params.num_subgroups; i++) {
+        bass_params.subgroups[i].bis_sync_state = state->subgroups[i].bis_sync;
+        bass_params.subgroups[i].metadata_length = 
state->subgroups[i].metadata_length;
+        bass_params.subgroups[i].metadata = state->subgroups[i].metadata;
+    }
+
+    rc = ble_svc_audio_bass_receive_state_update(&bass_params, source_id);
+    if (rc != 0) {
+        BLE_HS_LOG_ERROR("Failed to update receive state (rc %d)\n", rc);
+    }
+
+    return 0;
+}
+
+void
+ble_audio_scan_delegator_receive_state_foreach(ble_audio_scan_delegator_receive_state_foreach_fn
 *fn, void *arg)
+{
+    struct ble_audio_scan_delegator_receive_state_entry entry;
+    int rc;
+
+    if (fn == NULL) {
+        BLE_HS_LOG_ERROR("callback is NULL\n");
+        return;
+    }
+
+    for (int i = 0; i < 
MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_RECEIVE_STATE_MAX); i++) {
+        struct ble_svc_audio_bass_receiver_state *state;
+        uint8_t source_id;
+
+        rc = ble_svc_audio_bass_source_id_get(i, &source_id);
+        if (rc != 0) {
+            continue;
+        }
+
+        rc = ble_svc_audio_bass_receiver_state_get(source_id, &state);
+        if (rc != 0) {
+            BLE_HS_LOG_ERROR("Failed to get receiver state (rc %d)\n", rc);
+            continue;
+        }
+
+        entry.source_id = source_id;
+        source_desc_init(&entry.source_desc, &state->source_addr, 
state->source_adv_sid, state->source_adv_sid);
+        entry.state.pa_sync_state = (uint8_t)state->pa_sync_state;
+        entry.state.big_enc = (uint8_t)state->big_encryption;
+        if (entry.state.big_enc == 
BLE_AUDIO_SCAN_DELEGATOR_BIG_ENC_BROADCAST_CODE_INVALID) {
+            memcpy(entry.state.bad_code, state->bad_code, 
sizeof(entry.state.bad_code));
+        }
+        entry.state.num_subgroups = state->num_subgroups;
+        subgroups_init(entry.state.subgroups, state->subgroups, 
state->num_subgroups);
+
+        if (fn(&entry, arg) != 0) {
+            break;
+        }
+    }
+}
+
+#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)
+static int
+audio_event_handler(struct ble_audio_event *event, void *arg)
+{
+    if (event->type == BLE_AUDIO_EVENT_BASS_BROADCAST_CODE_SET) {
+        
ble_audio_broadcast_sink_code_set(event->bass_set_broadcast_code.source_id,
+                                          
event->bass_set_broadcast_code.broadcast_code);
+    }
+
+    return 0;
+}
+#endif /* BLE_AUDIO_BROADCAST_SINK */
+
+int
+ble_audio_scan_delegator_init(void)
+{
+    int rc;
+
+    /* Ensure this function only gets called by sysinit. */
+    SYSINIT_ASSERT_ACTIVE();
+
+#if MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK)
+    static struct ble_audio_event_listener listener;
+
+    rc = ble_audio_event_listener_register(&listener, audio_event_handler, 
NULL);
+    SYSINIT_PANIC_ASSERT(rc == 0);
+#endif /* BLE_AUDIO_BROADCAST_SINK */
+
+    return rc;
+}
+#endif /* BLE_AUDIO_SCAN_DELEGATOR */
diff --git a/nimble/host/audio/src/ble_audio_priv.h 
b/nimble/host/audio/src/ble_audio_scan_delegator_priv.h
similarity index 63%
copy from nimble/host/audio/src/ble_audio_priv.h
copy to nimble/host/audio/src/ble_audio_scan_delegator_priv.h
index 10f0109d..ae5fc651 100644
--- a/nimble/host/audio/src/ble_audio_priv.h
+++ b/nimble/host/audio/src/ble_audio_scan_delegator_priv.h
@@ -17,11 +17,17 @@
  * under the License.
  */
 
-#ifndef H_BLE_AUDIO_PRIV_
-#define H_BLE_AUDIO_PRIV_
+#ifndef H_BLE_AUDIO_SCAN_DELEGATOR_PRIV_
+#define H_BLE_AUDIO_SCAN_DELEGATOR_PRIV_
 
+#include <stdint.h>
 #include "audio/ble_audio.h"
+#include "audio/ble_audio_scan_delegator.h"
 
-int ble_audio_event_listener_call(struct ble_audio_event *event);
+int ble_audio_scan_delegator_source_desc_get(
+        uint8_t source_id, struct ble_audio_scan_delegator_source_desc 
*source_desc);
+int ble_audio_scan_delegator_metadata_update(
+        uint8_t source_id, uint8_t subgroup_index, const uint8_t *metadata,
+        uint8_t metadata_length);
 
-#endif /* H_BLE_AUDIO_PRIV_ */
+#endif /* H_BLE_AUDIO_SCAN_DELEGATOR_PRIV_ */
diff --git a/nimble/host/audio/syscfg.yml b/nimble/host/audio/syscfg.yml
index 5f0269e0..5368e503 100644
--- a/nimble/host/audio/syscfg.yml
+++ b/nimble/host/audio/syscfg.yml
@@ -16,10 +16,87 @@
 # under the License.
 #
 
+# syscfg.defs section
 syscfg.defs:
     BLE_AUDIO_MAX_CODEC_RECORDS:
         description: >
             Maximum number of registered audio codecs.
         value: 0
 
-syscfg.logs:
+    BLE_AUDIO_BROADCAST_SINK:
+        description: >
+            This option enables BLE Audio Sink support.
+        value: 0
+        restrictions:
+          - '(BLE_ISO_BROADCAST_SINK > 0) if 1'
+
+    BLE_AUDIO_SCAN_DELEGATOR:
+        description: >
+            This option enables BLE Audio Scan Delegator support.
+        value: 0
+
+syscfg.defs.BLE_AUDIO_BROADCAST_SINK:
+    BLE_AUDIO_BROADCAST_SINK_SYSINIT_STAGE:
+        description: >
+            Primary sysinit stage for BLE Audio Broadcast Sink.
+        value: 500
+
+    BLE_AUDIO_BROADCAST_SINK_LOG_MOD:
+        description: 'Numeric module ID to use for BLE Audio Broadcast Sink 
log messages.'
+        value: 28
+
+    BLE_AUDIO_BROADCAST_SINK_LOG_LVL:
+        description: 'Minimum level for the BLE Audio Broadcast Sink log log.'
+        value: 1
+
+    BLE_AUDIO_BROADCAST_SINK_MAX:
+        description: >
+            Maximum umber of Audio Broadcast Sink instances.
+        value: 'MYNEWT_VAL_BLE_ISO_MAX_BIGS'
+
+syscfg.defs.BLE_AUDIO_SCAN_DELEGATOR:
+    BLE_AUDIO_SCAN_DELEGATOR_SYSINIT_STAGE:
+        description: >
+            Primary sysinit stage for BLE Audio Scan Delegator.
+        value: 499
+
+    BLE_AUDIO_SCAN_DELEGATOR_LOG_MOD:
+        description: 'Numeric module ID to use for BLE Audio Scan Delegator 
log messages.'
+        value: 29
+
+    BLE_AUDIO_SCAN_DELEGATOR_LOG_LVL:
+        description: 'Minimum level for the BLE Audio Scan Delegator log log.'
+        value: 1
+
+    BLE_AUDIO_SCAN_DELEGATOR_RECEIVE_STATE_MAX:
+        description: >
+            Maximum number of Receive State instances.
+        value: MYNEWT_VAL(BLE_SVC_AUDIO_BASS_RECEIVE_STATE_MAX)
+
+    BLE_AUDIO_SCAN_DELEGATOR_SUBGROUP_MAX:
+        description: >
+            Maximum number of Subgroups per Receive State.
+        value: MYNEWT_VAL(BLE_SVC_AUDIO_BASS_SUB_NUM_MAX)
+
+    BLE_AUDIO_SCAN_DELEGATOR_STANDALONE:
+        description: >
+            This option enables the BLE Audio Scan Delegator as standalone 
device.
+        value: 1
+        restrictions:
+            - '(BLE_AUDIO_BROADCAST_SINK == 0) if 1'
+
+# syscfg.logs section
+syscfg.logs.BLE_AUDIO_BROADCAST_SINK:
+    BLE_AUDIO_BROADCAST_SINK_LOG:
+        module: MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_LOG_MOD)
+        level: MYNEWT_VAL(BLE_AUDIO_BROADCAST_SINK_LOG_LVL)
+
+syscfg.logs.BLE_AUDIO_SCAN_DELEGATOR:
+    BLE_AUDIO_SCAN_DELEGATOR_LOG:
+        module: MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_LOG_MOD)
+        level: MYNEWT_VAL(BLE_AUDIO_SCAN_DELEGATOR_LOG_LVL)
+
+# syscfg.vals section
+syscfg.vals.BLE_AUDIO_BROADCAST_SINK:
+    BLE_AUDIO_SCAN_DELEGATOR: 1
+    BLE_AUDIO_SCAN_DELEGATOR_STANDALONE: 0

Reply via email to