bumble 0.0.198__py3-none-any.whl → 0.0.200__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.
@@ -27,6 +27,7 @@ from bumble.colors import color
27
27
  from bumble.core import name_or_number
28
28
  from bumble.hci import (
29
29
  map_null_terminated_utf8_string,
30
+ CodecID,
30
31
  LeFeature,
31
32
  HCI_SUCCESS,
32
33
  HCI_VERSION_NAMES,
@@ -50,6 +51,8 @@ from bumble.hci import (
50
51
  HCI_LE_Read_Maximum_Advertising_Data_Length_Command,
51
52
  HCI_LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH_COMMAND,
52
53
  HCI_LE_Read_Suggested_Default_Data_Length_Command,
54
+ HCI_Read_Local_Supported_Codecs_Command,
55
+ HCI_Read_Local_Supported_Codecs_V2_Command,
53
56
  HCI_Read_Local_Version_Information_Command,
54
57
  )
55
58
  from bumble.host import Host
@@ -168,6 +171,60 @@ async def get_acl_flow_control_info(host: Host) -> None:
168
171
  )
169
172
 
170
173
 
174
+ # -----------------------------------------------------------------------------
175
+ async def get_codecs_info(host: Host) -> None:
176
+ print()
177
+
178
+ if host.supports_command(HCI_Read_Local_Supported_Codecs_V2_Command.op_code):
179
+ response = await host.send_command(
180
+ HCI_Read_Local_Supported_Codecs_V2_Command(), check_result=True
181
+ )
182
+ print(color('Codecs:', 'yellow'))
183
+
184
+ for codec_id, transport in zip(
185
+ response.return_parameters.standard_codec_ids,
186
+ response.return_parameters.standard_codec_transports,
187
+ ):
188
+ transport_name = HCI_Read_Local_Supported_Codecs_V2_Command.Transport(
189
+ transport
190
+ ).name
191
+ codec_name = CodecID(codec_id).name
192
+ print(f' {codec_name} - {transport_name}')
193
+
194
+ for codec_id, transport in zip(
195
+ response.return_parameters.vendor_specific_codec_ids,
196
+ response.return_parameters.vendor_specific_codec_transports,
197
+ ):
198
+ transport_name = HCI_Read_Local_Supported_Codecs_V2_Command.Transport(
199
+ transport
200
+ ).name
201
+ company = name_or_number(COMPANY_IDENTIFIERS, codec_id >> 16)
202
+ print(f' {company} / {codec_id & 0xFFFF} - {transport_name}')
203
+
204
+ if not response.return_parameters.standard_codec_ids:
205
+ print(' No standard codecs')
206
+ if not response.return_parameters.vendor_specific_codec_ids:
207
+ print(' No Vendor-specific codecs')
208
+
209
+ if host.supports_command(HCI_Read_Local_Supported_Codecs_Command.op_code):
210
+ response = await host.send_command(
211
+ HCI_Read_Local_Supported_Codecs_Command(), check_result=True
212
+ )
213
+ print(color('Codecs (BR/EDR):', 'yellow'))
214
+ for codec_id in response.return_parameters.standard_codec_ids:
215
+ codec_name = CodecID(codec_id).name
216
+ print(f' {codec_name}')
217
+
218
+ for codec_id in response.return_parameters.vendor_specific_codec_ids:
219
+ company = name_or_number(COMPANY_IDENTIFIERS, codec_id >> 16)
220
+ print(f' {company} / {codec_id & 0xFFFF}')
221
+
222
+ if not response.return_parameters.standard_codec_ids:
223
+ print(' No standard codecs')
224
+ if not response.return_parameters.vendor_specific_codec_ids:
225
+ print(' No Vendor-specific codecs')
226
+
227
+
171
228
  # -----------------------------------------------------------------------------
172
229
  async def async_main(latency_probes, transport):
173
230
  print('<<< connecting to HCI...')
@@ -220,6 +277,9 @@ async def async_main(latency_probes, transport):
220
277
  # Print the ACL flow control info
221
278
  await get_acl_flow_control_info(host)
222
279
 
280
+ # Get codec info
281
+ await get_codecs_info(host)
282
+
223
283
  # Print the list of commands supported by the controller
224
284
  print()
225
285
  print(color('Supported Commands:', 'yellow'))
bumble/apps/pair.py CHANGED
@@ -46,6 +46,12 @@ from bumble.att import (
46
46
  ATT_INSUFFICIENT_AUTHENTICATION_ERROR,
47
47
  ATT_INSUFFICIENT_ENCRYPTION_ERROR,
48
48
  )
49
+ from bumble.utils import AsyncRunner
50
+
51
+ # -----------------------------------------------------------------------------
52
+ # Constants
53
+ # -----------------------------------------------------------------------------
54
+ POST_PAIRING_DELAY = 1
49
55
 
50
56
 
51
57
  # -----------------------------------------------------------------------------
@@ -235,8 +241,10 @@ def on_connection(connection, request):
235
241
 
236
242
  # Listen for pairing events
237
243
  connection.on('pairing_start', on_pairing_start)
238
- connection.on('pairing', lambda keys: on_pairing(connection.peer_address, keys))
239
- connection.on('pairing_failure', on_pairing_failure)
244
+ connection.on('pairing', lambda keys: on_pairing(connection, keys))
245
+ connection.on(
246
+ 'pairing_failure', lambda reason: on_pairing_failure(connection, reason)
247
+ )
240
248
 
241
249
  # Listen for encryption changes
242
250
  connection.on(
@@ -270,19 +278,24 @@ def on_pairing_start():
270
278
 
271
279
 
272
280
  # -----------------------------------------------------------------------------
273
- def on_pairing(address, keys):
281
+ @AsyncRunner.run_in_task()
282
+ async def on_pairing(connection, keys):
274
283
  print(color('***-----------------------------------', 'cyan'))
275
- print(color(f'*** Paired! (peer identity={address})', 'cyan'))
284
+ print(color(f'*** Paired! (peer identity={connection.peer_address})', 'cyan'))
276
285
  keys.print(prefix=color('*** ', 'cyan'))
277
286
  print(color('***-----------------------------------', 'cyan'))
287
+ await asyncio.sleep(POST_PAIRING_DELAY)
288
+ await connection.disconnect()
278
289
  Waiter.instance.terminate()
279
290
 
280
291
 
281
292
  # -----------------------------------------------------------------------------
282
- def on_pairing_failure(reason):
293
+ @AsyncRunner.run_in_task()
294
+ async def on_pairing_failure(connection, reason):
283
295
  print(color('***-----------------------------------', 'red'))
284
296
  print(color(f'*** Pairing failed: {smp_error_name(reason)}', 'red'))
285
297
  print(color('***-----------------------------------', 'red'))
298
+ await connection.disconnect()
286
299
  Waiter.instance.terminate()
287
300
 
288
301
 
@@ -293,6 +306,7 @@ async def pair(
293
306
  mitm,
294
307
  bond,
295
308
  ctkd,
309
+ identity_address,
296
310
  linger,
297
311
  io,
298
312
  oob,
@@ -382,11 +396,18 @@ async def pair(
382
396
  oob_contexts = None
383
397
 
384
398
  # Set up a pairing config factory
399
+ if identity_address == 'public':
400
+ identity_address_type = PairingConfig.AddressType.PUBLIC
401
+ elif identity_address == 'random':
402
+ identity_address_type = PairingConfig.AddressType.RANDOM
403
+ else:
404
+ identity_address_type = None
385
405
  device.pairing_config_factory = lambda connection: PairingConfig(
386
406
  sc=sc,
387
407
  mitm=mitm,
388
408
  bonding=bond,
389
409
  oob=oob_contexts,
410
+ identity_address_type=identity_address_type,
390
411
  delegate=Delegate(mode, connection, io, prompt),
391
412
  )
392
413
 
@@ -457,6 +478,10 @@ class LogHandler(logging.Handler):
457
478
  help='Enable CTKD',
458
479
  show_default=True,
459
480
  )
481
+ @click.option(
482
+ '--identity-address',
483
+ type=click.Choice(['random', 'public']),
484
+ )
460
485
  @click.option('--linger', default=False, is_flag=True, help='Linger after pairing')
461
486
  @click.option(
462
487
  '--io',
@@ -493,6 +518,7 @@ def main(
493
518
  mitm,
494
519
  bond,
495
520
  ctkd,
521
+ identity_address,
496
522
  linger,
497
523
  io,
498
524
  oob,
@@ -518,6 +544,7 @@ def main(
518
544
  mitm,
519
545
  bond,
520
546
  ctkd,
547
+ identity_address,
521
548
  linger,
522
549
  io,
523
550
  oob,