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.
- bumble/_version.py +2 -2
- bumble/a2dp.py +502 -202
- bumble/apps/controller_info.py +60 -0
- bumble/apps/pair.py +32 -5
- bumble/apps/player/player.py +608 -0
- bumble/apps/speaker/speaker.py +25 -27
- bumble/att.py +57 -41
- bumble/avc.py +1 -2
- bumble/avdtp.py +56 -99
- bumble/avrcp.py +48 -29
- bumble/codecs.py +214 -68
- bumble/decoder.py +14 -10
- bumble/device.py +19 -11
- bumble/drivers/rtk.py +19 -5
- bumble/gatt.py +24 -19
- bumble/gatt_client.py +5 -25
- bumble/gatt_server.py +14 -6
- bumble/hci.py +298 -7
- bumble/hfp.py +52 -48
- bumble/host.py +28 -6
- bumble/pandora/__init__.py +3 -0
- bumble/pandora/l2cap.py +310 -0
- bumble/profiles/aics.py +520 -0
- bumble/profiles/asha.py +295 -0
- bumble/profiles/hap.py +674 -0
- bumble/profiles/vcp.py +5 -3
- bumble/rtp.py +110 -0
- bumble/smp.py +23 -4
- bumble/transport/android_netsim.py +3 -0
- bumble/transport/pyusb.py +20 -2
- {bumble-0.0.198.dist-info → bumble-0.0.200.dist-info}/METADATA +2 -2
- {bumble-0.0.198.dist-info → bumble-0.0.200.dist-info}/RECORD +36 -31
- {bumble-0.0.198.dist-info → bumble-0.0.200.dist-info}/WHEEL +1 -1
- {bumble-0.0.198.dist-info → bumble-0.0.200.dist-info}/entry_points.txt +1 -0
- bumble/profiles/asha_service.py +0 -193
- {bumble-0.0.198.dist-info → bumble-0.0.200.dist-info}/LICENSE +0 -0
- {bumble-0.0.198.dist-info → bumble-0.0.200.dist-info}/top_level.txt +0 -0
bumble/apps/controller_info.py
CHANGED
|
@@ -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
|
|
239
|
-
connection.on(
|
|
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
|
-
|
|
281
|
+
@AsyncRunner.run_in_task()
|
|
282
|
+
async def on_pairing(connection, keys):
|
|
274
283
|
print(color('***-----------------------------------', 'cyan'))
|
|
275
|
-
print(color(f'*** Paired! (peer identity={
|
|
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
|
-
|
|
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,
|