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 CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.0.202'
16
- __version_tuple__ = version_tuple = (0, 0, 202)
15
+ __version__ = version = '0.0.203'
16
+ __version_tuple__ = version_tuple = (0, 0, 203)
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
- print(f' {color("Name", "cyan")}: {self.name}')
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.coding_format.name,
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
- broadcast_name := advertisement.data.get(
279
- bumble.core.AdvertisingData.BROADCAST_NAME
278
+ if not (
279
+ ads := advertisement.data.get_all(
280
+ bumble.core.AdvertisingData.SERVICE_DATA_16_BIT_UUID
280
281
  )
281
- ) is None:
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
- assert isinstance(broadcast_name, str)
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
@@ -83,7 +83,7 @@ async def async_main():
83
83
  return_parameters=bytes([hci.HCI_SUCCESS]),
84
84
  )
85
85
  # Return a packet with 'respond to sender' set to True
86
- return (response.to_bytes(), True)
86
+ return (bytes(response), True)
87
87
 
88
88
  return None
89
89
 
@@ -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
- assert isinstance(codec_config, bap.CodecSpecificConfiguration)
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
- codec_config = ase.codec_specific_configuration
520
- assert isinstance(codec_config, bap.CodecSpecificConfiguration)
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.to_bytes()
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.to_bytes())
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.to_bytes()
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