This registers a control point handler with shared/bass, for each eastablished BASS session. For now, only the Add Source opcode is handled. Using the parameters provided from shared/bass, a device is created for the Broadcaster address. The device is then probed with BAP, where long-lived PA sync will be established. After parsing the BASE, transports are created for each BIS, as if the Broadcast Sink scanned the Broadacaster autonomously. Below is a bluetoothctl log which shows a Scan Delegator starting to advertise, connecting to a Broadcast Assistant, receiving the Add Source command for a Broadcaster streaming one BIS, creating a device for the Broadcaster and then creating a transport for the BIS: client/bluetoothctl [bluetooth]# endpoint.register 00001851-0000-1000-8000-00805f9b34fb 0x06 [/local/endpoint/ep0] Auto Accept (yes/no): y [/local/endpoint/ep0] Max Transports (auto/value): a [/local/endpoint/ep0] Locations: 1 [/local/endpoint/ep0] Supported Context (value): 1 [bluetooth]# Endpoint /local/endpoint/ep0 registered [bluetooth]# advertise on [bluetooth]# [NEW] Device 00:60:37:31:7E:3F 00-60-37-31-7E-3F [00-60-37-31-7E-3F]# [NEW] Device 03:E2:C0:11:57:DA 03-E2-C0-11-57-DA [00-60-37-31-7E-3F]# [NEW] Transport /org/bluez/hci1/dev_03_E2_C0_11_57_DA/bis1/fd0 The btmon log below shows the GATT write command with the Add Source opcode, which was received from the Broadcast Assistant. It also shows the long-lived PA sync performed by BAP: > ACL Data RX: Handle 0 flags 0x01 dlen 1 ATT: Write Command (0x52) len 23 Handle: 0x0040 Type: Broadcast Audio Scan Control Point (0x2bc7) Data[21]: 0201da5711c0e203001a2d5602ffff010100000000 Opcode: Add Source (0x02) Source_Address_Type: 1 Source_Address: 03:E2:C0:11:57:DA Source_Adv_SID: 0 Broadcast_ID: 0x562d1a PA_Sync_State: Synchronize to PA - PAST not available PA_Interval: 0xffff Num_Subgroups: 1 Subgroup #0: BIS_Sync State: 0x00000001 < HCI Command: LE Periodic Advertising Create Sync (0x08|0x0044) Options: 0x0000 Use advertising SID, Advertiser Address Type and address Reporting initially enabled SID: 0x00 Adv address type: Random (0x01) Adv address: 03:E2:C0:11:57:DA (Non-Resolvable) Skip: 0x0000 Sync timeout: 20000 msec (0x07d0) Sync CTE type: 0x0000 > HCI Event: Command Status (0x0f) plen 4 LE Periodic Advertising Create Sync (0x08|0x0044) ncmd 1 Status: Success (0x00) > HCI Event: LE Meta Event (0x3e) plen 16 LE Periodic Advertising Sync Established (0x0e) Status: Success (0x00) Sync handle: 0 Advertising SID: 0x00 Advertiser address type: Random (0x01) Advertiser address: 03:E2:C0:11:57:DA (Non-Resolvable) Advertiser PHY: LE 2M (0x02) Periodic advertising interval: 10.00 msec (0x0008) Advertiser clock accuracy: 0x07 > HCI Event: LE Meta Event (0x3e) plen 42 LE Periodic Advertising Report (0x0f) Sync handle: 0 TX power: 127 dbm (0x7f) RSSI: -64 dBm (0xc0) CTE Type: No Constant Tone Extension (0xff) Data status: Complete Data length: 0x22 Service Data: Basic Audio Announcement (0x1851) Presetation Delay: 40000 Number of Subgroups: 1 Subgroup #0: Number of BIS(s): 1 Codec: LC3 (0x06) Codec Specific Configuration: #0: len 0x02 type 0x01 Codec Specific Configuration: Sampling Frequency: 16 Khz Codec Specific Configuration: #1: len 0x02 type 0x02 Codec Specific Configuration: Frame Duration: 10 ms (0x01) Codec Specific Configuration: #2: len 0x03 type 0x04 Codec Specific Configuration: Frame Length: 40 (0x0028) Codec Specific Configuration: #3: len 0x05 type 0x03 Codec Specific Configuration: Location: 0x00000001 Codec Specific Configuration: Location: Front Left BIS #0: Index: 1 > HCI Event: LE Meta Event (0x3e) plen 20 LE Broadcast Isochronous Group Info Advertising Report (0x22) Sync Handle: 0x0000 Number BIS: 1 NSE: 3 ISO Interval: 10.00 msec (0x0008) BN: 1 PTO: 1 IRC: 3 Maximum PDU: 40 SDU Interval: 10000 us (0x002710) Maximum SDU: 40 PHY: LE 2M (0x02) Framing: Unframed (0x00) Encryption: 0x00 --- profiles/audio/bass.c | 79 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/profiles/audio/bass.c b/profiles/audio/bass.c index b3740f64e..ee378e141 100644 --- a/profiles/audio/bass.c +++ b/profiles/audio/bass.c @@ -54,6 +54,7 @@ #include "bap.h" #define BASS_UUID_STR "0000184f-0000-1000-8000-00805f9b34fb" +#define BCAAS_UUID_STR "00001852-0000-1000-8000-00805f9b34fb" #define MEDIA_ASSISTANT_INTERFACE "org.bluez.MediaAssistant1" @@ -82,6 +83,7 @@ struct bass_data { struct btd_service *service; struct bt_bass *bass; unsigned int src_id; + unsigned int cp_id; }; struct bass_assistant { @@ -97,8 +99,14 @@ struct bass_assistant { char *path; }; +struct bass_delegator { + struct btd_device *device; /* Broadcast source device */ + struct bt_bcast_src *src; +}; + static struct queue *sessions; static struct queue *assistants; +static struct queue *delegators; static const char *state2str(enum assistant_state state); @@ -582,6 +590,7 @@ static void bass_data_free(struct bass_data *data) } bt_bass_src_unregister(data->bass, data->src_id); + bt_bass_cp_handler_unregister(data->bass, data->cp_id); bt_bass_unref(data->bass); @@ -627,6 +636,70 @@ static void bass_detached(struct bt_bass *bass, void *user_data) bass_data_remove(data); } +static int handle_add_src_req(struct bt_bcast_src *bcast_src, + struct bt_bass_add_src_params *params, + struct bass_data *data) +{ + struct btd_adapter *adapter = device_get_adapter(data->device); + struct btd_device *device; + struct bass_delegator *dg; + + /* Create device for Broadcast Source using the parameters + * provided by Broadcast Assistant. + */ + device = btd_adapter_get_device(adapter, ¶ms->addr, + params->addr_type); + if (!device) { + DBG("Unable to get device"); + return -EINVAL; + } + + DBG("device %p", device); + + /* Probe Broadcast Source, if it has not already been + * autonomously probed inside BAP. + */ + if (!btd_device_get_service(device, BCAAS_UUID_STR)) + goto probe; + + return 0; + +probe: + dg = new0(struct bass_delegator, 1); + if (!dg) + return -ENOMEM; + + dg->device = device; + dg->src = bcast_src; + + if (!delegators) + delegators = queue_new(); + + queue_push_tail(delegators, dg); + + DBG("delegator %p", dg); + + /* Probe device with BAP. */ + bap_scan_delegator_probe(device); + + return 0; +} + +static int cp_handler(struct bt_bcast_src *bcast_src, uint8_t op, void *params, + void *user_data) +{ + struct bass_data *data = user_data; + int err = 0; + + switch (op) { + case BT_BASS_ADD_SRC: + err = handle_add_src_req(bcast_src, params, data); + break; + } + + return err; +} + static void bass_attached(struct bt_bass *bass, void *user_data) { struct bass_data *data; @@ -652,6 +725,9 @@ static void bass_attached(struct bt_bass *bass, void *user_data) data = bass_data_new(device); data->bass = bass; + data->cp_id = bt_bass_cp_handler_register(data->bass, + cp_handler, NULL, data); + bass_data_add(data); } @@ -780,6 +856,9 @@ static int bass_probe(struct btd_service *service) data->src_id = bt_bass_src_register(data->bass, bass_src_changed, data, NULL); + data->cp_id = bt_bass_cp_handler_register(data->bass, + cp_handler, NULL, data); + return 0; } -- 2.39.2