bumble 0.0.202__py3-none-any.whl → 0.0.203__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bumble/_version.py +2 -2
- bumble/apps/auracast.py +22 -13
- bumble/apps/hci_bridge.py +1 -1
- bumble/apps/lea_unicast/app.py +24 -6
- bumble/att.py +1 -4
- bumble/controller.py +58 -2
- bumble/device.py +454 -494
- bumble/gatt.py +1 -1
- bumble/gatt_client.py +3 -3
- bumble/gatt_server.py +2 -2
- bumble/hci.py +93 -33
- bumble/hfp.py +20 -17
- bumble/host.py +1 -1
- bumble/l2cap.py +2 -8
- bumble/pandora/host.py +1 -1
- bumble/profiles/aics.py +3 -3
- bumble/profiles/bap.py +114 -42
- bumble/sdp.py +1 -7
- bumble/smp.py +2 -5
- {bumble-0.0.202.dist-info → bumble-0.0.203.dist-info}/METADATA +15 -15
- {bumble-0.0.202.dist-info → bumble-0.0.203.dist-info}/RECORD +25 -25
- {bumble-0.0.202.dist-info → bumble-0.0.203.dist-info}/WHEEL +1 -1
- {bumble-0.0.202.dist-info → bumble-0.0.203.dist-info}/LICENSE +0 -0
- {bumble-0.0.202.dist-info → bumble-0.0.203.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.202.dist-info → bumble-0.0.203.dist-info}/top_level.txt +0 -0
bumble/_version.py
CHANGED
bumble/apps/auracast.py
CHANGED
|
@@ -60,7 +60,7 @@ AURACAST_DEFAULT_ATT_MTU = 256
|
|
|
60
60
|
class BroadcastScanner(pyee.EventEmitter):
|
|
61
61
|
@dataclasses.dataclass
|
|
62
62
|
class Broadcast(pyee.EventEmitter):
|
|
63
|
-
name: str
|
|
63
|
+
name: str | None
|
|
64
64
|
sync: bumble.device.PeriodicAdvertisingSync
|
|
65
65
|
rssi: int = 0
|
|
66
66
|
public_broadcast_announcement: Optional[
|
|
@@ -135,7 +135,8 @@ class BroadcastScanner(pyee.EventEmitter):
|
|
|
135
135
|
self.sync.advertiser_address,
|
|
136
136
|
color(self.sync.state.name, 'green'),
|
|
137
137
|
)
|
|
138
|
-
|
|
138
|
+
if self.name is not None:
|
|
139
|
+
print(f' {color("Name", "cyan")}: {self.name}')
|
|
139
140
|
if self.appearance:
|
|
140
141
|
print(f' {color("Appearance", "cyan")}: {str(self.appearance)}')
|
|
141
142
|
print(f' {color("RSSI", "cyan")}: {self.rssi}')
|
|
@@ -174,7 +175,7 @@ class BroadcastScanner(pyee.EventEmitter):
|
|
|
174
175
|
print(color(' Codec ID:', 'yellow'))
|
|
175
176
|
print(
|
|
176
177
|
color(' Coding Format: ', 'green'),
|
|
177
|
-
subgroup.codec_id.
|
|
178
|
+
subgroup.codec_id.codec_id.name,
|
|
178
179
|
)
|
|
179
180
|
print(
|
|
180
181
|
color(' Company ID: ', 'green'),
|
|
@@ -274,13 +275,24 @@ class BroadcastScanner(pyee.EventEmitter):
|
|
|
274
275
|
await self.device.stop_scanning()
|
|
275
276
|
|
|
276
277
|
def on_advertisement(self, advertisement: bumble.device.Advertisement) -> None:
|
|
277
|
-
if (
|
|
278
|
-
|
|
279
|
-
bumble.core.AdvertisingData.
|
|
278
|
+
if not (
|
|
279
|
+
ads := advertisement.data.get_all(
|
|
280
|
+
bumble.core.AdvertisingData.SERVICE_DATA_16_BIT_UUID
|
|
280
281
|
)
|
|
281
|
-
)
|
|
282
|
+
) or not (
|
|
283
|
+
any(
|
|
284
|
+
ad
|
|
285
|
+
for ad in ads
|
|
286
|
+
if isinstance(ad, tuple)
|
|
287
|
+
and ad[0] == bumble.gatt.GATT_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE
|
|
288
|
+
)
|
|
289
|
+
):
|
|
282
290
|
return
|
|
283
|
-
|
|
291
|
+
|
|
292
|
+
broadcast_name = advertisement.data.get(
|
|
293
|
+
bumble.core.AdvertisingData.BROADCAST_NAME
|
|
294
|
+
)
|
|
295
|
+
assert isinstance(broadcast_name, str) or broadcast_name is None
|
|
284
296
|
|
|
285
297
|
if broadcast := self.broadcasts.get(advertisement.address):
|
|
286
298
|
broadcast.update(advertisement)
|
|
@@ -291,7 +303,7 @@ class BroadcastScanner(pyee.EventEmitter):
|
|
|
291
303
|
)
|
|
292
304
|
|
|
293
305
|
async def on_new_broadcast(
|
|
294
|
-
self, name: str, advertisement: bumble.device.Advertisement
|
|
306
|
+
self, name: str | None, advertisement: bumble.device.Advertisement
|
|
295
307
|
) -> None:
|
|
296
308
|
periodic_advertising_sync = await self.device.create_periodic_advertising_sync(
|
|
297
309
|
advertiser_address=advertisement.address,
|
|
@@ -299,10 +311,7 @@ class BroadcastScanner(pyee.EventEmitter):
|
|
|
299
311
|
sync_timeout=self.sync_timeout,
|
|
300
312
|
filter_duplicates=self.filter_duplicates,
|
|
301
313
|
)
|
|
302
|
-
broadcast = self.Broadcast(
|
|
303
|
-
name,
|
|
304
|
-
periodic_advertising_sync,
|
|
305
|
-
)
|
|
314
|
+
broadcast = self.Broadcast(name, periodic_advertising_sync)
|
|
306
315
|
broadcast.update(advertisement)
|
|
307
316
|
self.broadcasts[advertisement.address] = broadcast
|
|
308
317
|
periodic_advertising_sync.on('loss', lambda: self.on_broadcast_loss(broadcast))
|
bumble/apps/hci_bridge.py
CHANGED
bumble/apps/lea_unicast/app.py
CHANGED
|
@@ -486,7 +486,12 @@ class Speaker:
|
|
|
486
486
|
|
|
487
487
|
def on_pdu(pdu: HCI_IsoDataPacket, ase: ascs.AseStateMachine):
|
|
488
488
|
codec_config = ase.codec_specific_configuration
|
|
489
|
-
|
|
489
|
+
if (
|
|
490
|
+
not isinstance(codec_config, bap.CodecSpecificConfiguration)
|
|
491
|
+
or codec_config.frame_duration is None
|
|
492
|
+
or codec_config.audio_channel_allocation is None
|
|
493
|
+
):
|
|
494
|
+
return
|
|
490
495
|
pcm = decode(
|
|
491
496
|
codec_config.frame_duration.us,
|
|
492
497
|
codec_config.audio_channel_allocation.channel_count,
|
|
@@ -495,11 +500,17 @@ class Speaker:
|
|
|
495
500
|
self.device.abort_on('disconnection', self.ui_server.send_audio(pcm))
|
|
496
501
|
|
|
497
502
|
def on_ase_state_change(ase: ascs.AseStateMachine) -> None:
|
|
503
|
+
codec_config = ase.codec_specific_configuration
|
|
498
504
|
if ase.state == ascs.AseStateMachine.State.STREAMING:
|
|
499
|
-
codec_config = ase.codec_specific_configuration
|
|
500
|
-
assert isinstance(codec_config, bap.CodecSpecificConfiguration)
|
|
501
|
-
assert ase.cis_link
|
|
502
505
|
if ase.role == ascs.AudioRole.SOURCE:
|
|
506
|
+
if (
|
|
507
|
+
not isinstance(codec_config, bap.CodecSpecificConfiguration)
|
|
508
|
+
or ase.cis_link is None
|
|
509
|
+
or codec_config.octets_per_codec_frame is None
|
|
510
|
+
or codec_config.frame_duration is None
|
|
511
|
+
or codec_config.codec_frames_per_sdu is None
|
|
512
|
+
):
|
|
513
|
+
return
|
|
503
514
|
ase.cis_link.abort_on(
|
|
504
515
|
'disconnection',
|
|
505
516
|
lc3_source_task(
|
|
@@ -514,10 +525,17 @@ class Speaker:
|
|
|
514
525
|
),
|
|
515
526
|
)
|
|
516
527
|
else:
|
|
528
|
+
if not ase.cis_link:
|
|
529
|
+
return
|
|
517
530
|
ase.cis_link.sink = functools.partial(on_pdu, ase=ase)
|
|
518
531
|
elif ase.state == ascs.AseStateMachine.State.CODEC_CONFIGURED:
|
|
519
|
-
|
|
520
|
-
|
|
532
|
+
if (
|
|
533
|
+
not isinstance(codec_config, bap.CodecSpecificConfiguration)
|
|
534
|
+
or codec_config.sampling_frequency is None
|
|
535
|
+
or codec_config.frame_duration is None
|
|
536
|
+
or codec_config.audio_channel_allocation is None
|
|
537
|
+
):
|
|
538
|
+
return
|
|
521
539
|
if ase.role == ascs.AudioRole.SOURCE:
|
|
522
540
|
setup_encoders(
|
|
523
541
|
codec_config.sampling_frequency.hz,
|
bumble/att.py
CHANGED
|
@@ -291,9 +291,6 @@ class ATT_PDU:
|
|
|
291
291
|
def init_from_bytes(self, pdu, offset):
|
|
292
292
|
return HCI_Object.init_from_bytes(self, pdu, offset, self.fields)
|
|
293
293
|
|
|
294
|
-
def to_bytes(self):
|
|
295
|
-
return self.pdu
|
|
296
|
-
|
|
297
294
|
@property
|
|
298
295
|
def is_command(self):
|
|
299
296
|
return ((self.op_code >> 6) & 1) == 1
|
|
@@ -303,7 +300,7 @@ class ATT_PDU:
|
|
|
303
300
|
return ((self.op_code >> 7) & 1) == 1
|
|
304
301
|
|
|
305
302
|
def __bytes__(self):
|
|
306
|
-
return self.
|
|
303
|
+
return self.pdu
|
|
307
304
|
|
|
308
305
|
def __str__(self):
|
|
309
306
|
result = color(self.name, 'yellow')
|
bumble/controller.py
CHANGED
|
@@ -314,7 +314,7 @@ class Controller:
|
|
|
314
314
|
f'{color("CONTROLLER -> HOST", "green")}: {packet}'
|
|
315
315
|
)
|
|
316
316
|
if self.host:
|
|
317
|
-
self.host.on_packet(packet
|
|
317
|
+
self.host.on_packet(bytes(packet))
|
|
318
318
|
|
|
319
319
|
# This method allows the controller to emulate the same API as a transport source
|
|
320
320
|
async def wait_for_termination(self):
|
|
@@ -1192,7 +1192,7 @@ class Controller:
|
|
|
1192
1192
|
See Bluetooth spec Vol 4, Part E - 7.4.6 Read BD_ADDR Command
|
|
1193
1193
|
'''
|
|
1194
1194
|
bd_addr = (
|
|
1195
|
-
self._public_address
|
|
1195
|
+
bytes(self._public_address)
|
|
1196
1196
|
if self._public_address is not None
|
|
1197
1197
|
else bytes(6)
|
|
1198
1198
|
)
|
|
@@ -1543,6 +1543,41 @@ class Controller:
|
|
|
1543
1543
|
}
|
|
1544
1544
|
return bytes([HCI_SUCCESS])
|
|
1545
1545
|
|
|
1546
|
+
def on_hci_le_set_advertising_set_random_address_command(self, _command):
|
|
1547
|
+
'''
|
|
1548
|
+
See Bluetooth spec Vol 4, Part E - 7.8.52 LE Set Advertising Set Random Address
|
|
1549
|
+
Command
|
|
1550
|
+
'''
|
|
1551
|
+
return bytes([HCI_SUCCESS])
|
|
1552
|
+
|
|
1553
|
+
def on_hci_le_set_extended_advertising_parameters_command(self, _command):
|
|
1554
|
+
'''
|
|
1555
|
+
See Bluetooth spec Vol 4, Part E - 7.8.53 LE Set Extended Advertising Parameters
|
|
1556
|
+
Command
|
|
1557
|
+
'''
|
|
1558
|
+
return bytes([HCI_SUCCESS, 0])
|
|
1559
|
+
|
|
1560
|
+
def on_hci_le_set_extended_advertising_data_command(self, _command):
|
|
1561
|
+
'''
|
|
1562
|
+
See Bluetooth spec Vol 4, Part E - 7.8.54 LE Set Extended Advertising Data
|
|
1563
|
+
Command
|
|
1564
|
+
'''
|
|
1565
|
+
return bytes([HCI_SUCCESS])
|
|
1566
|
+
|
|
1567
|
+
def on_hci_le_set_extended_scan_response_data_command(self, _command):
|
|
1568
|
+
'''
|
|
1569
|
+
See Bluetooth spec Vol 4, Part E - 7.8.55 LE Set Extended Scan Response Data
|
|
1570
|
+
Command
|
|
1571
|
+
'''
|
|
1572
|
+
return bytes([HCI_SUCCESS])
|
|
1573
|
+
|
|
1574
|
+
def on_hci_le_set_extended_advertising_enable_command(self, _command):
|
|
1575
|
+
'''
|
|
1576
|
+
See Bluetooth spec Vol 4, Part E - 7.8.56 LE Set Extended Advertising Enable
|
|
1577
|
+
Command
|
|
1578
|
+
'''
|
|
1579
|
+
return bytes([HCI_SUCCESS])
|
|
1580
|
+
|
|
1546
1581
|
def on_hci_le_read_maximum_advertising_data_length_command(self, _command):
|
|
1547
1582
|
'''
|
|
1548
1583
|
See Bluetooth spec Vol 4, Part E - 7.8.57 LE Read Maximum Advertising Data
|
|
@@ -1557,6 +1592,27 @@ class Controller:
|
|
|
1557
1592
|
'''
|
|
1558
1593
|
return struct.pack('<BB', HCI_SUCCESS, 0xF0)
|
|
1559
1594
|
|
|
1595
|
+
def on_hci_le_set_periodic_advertising_parameters_command(self, _command):
|
|
1596
|
+
'''
|
|
1597
|
+
See Bluetooth spec Vol 4, Part E - 7.8.61 LE Set Periodic Advertising Parameters
|
|
1598
|
+
Command
|
|
1599
|
+
'''
|
|
1600
|
+
return bytes([HCI_SUCCESS])
|
|
1601
|
+
|
|
1602
|
+
def on_hci_le_set_periodic_advertising_data_command(self, _command):
|
|
1603
|
+
'''
|
|
1604
|
+
See Bluetooth spec Vol 4, Part E - 7.8.62 LE Set Periodic Advertising Data
|
|
1605
|
+
Command
|
|
1606
|
+
'''
|
|
1607
|
+
return bytes([HCI_SUCCESS])
|
|
1608
|
+
|
|
1609
|
+
def on_hci_le_set_periodic_advertising_enable_command(self, _command):
|
|
1610
|
+
'''
|
|
1611
|
+
See Bluetooth spec Vol 4, Part E - 7.8.63 LE Set Periodic Advertising Enable
|
|
1612
|
+
Command
|
|
1613
|
+
'''
|
|
1614
|
+
return bytes([HCI_SUCCESS])
|
|
1615
|
+
|
|
1560
1616
|
def on_hci_le_read_transmit_power_command(self, _command):
|
|
1561
1617
|
'''
|
|
1562
1618
|
See Bluetooth spec Vol 4, Part E - 7.8.74 LE Read Transmit Power Command
|