bumble 0.0.212__py3-none-any.whl → 0.0.214__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 +6 -0
- bumble/apps/README.md +0 -3
- bumble/apps/auracast.py +14 -11
- bumble/apps/bench.py +482 -37
- bumble/apps/console.py +3 -3
- bumble/apps/controller_info.py +44 -12
- bumble/apps/controller_loopback.py +7 -7
- bumble/apps/controllers.py +4 -5
- bumble/apps/device_info.py +4 -5
- bumble/apps/gatt_dump.py +5 -5
- bumble/apps/gg_bridge.py +5 -5
- bumble/apps/hci_bridge.py +5 -4
- bumble/apps/l2cap_bridge.py +5 -5
- bumble/apps/lea_unicast/app.py +8 -3
- bumble/apps/pair.py +19 -11
- bumble/apps/pandora_server.py +2 -2
- bumble/apps/player/player.py +2 -3
- bumble/apps/rfcomm_bridge.py +3 -4
- bumble/apps/scan.py +4 -5
- bumble/apps/show.py +6 -4
- bumble/apps/speaker/speaker.html +1 -0
- bumble/apps/speaker/speaker.js +113 -62
- bumble/apps/speaker/speaker.py +123 -19
- bumble/apps/unbond.py +2 -3
- bumble/apps/usb_probe.py +2 -3
- bumble/at.py +4 -4
- bumble/att.py +2 -6
- bumble/avc.py +7 -7
- bumble/avctp.py +3 -3
- bumble/avdtp.py +16 -20
- bumble/avrcp.py +42 -54
- bumble/colors.py +2 -2
- bumble/controller.py +174 -45
- bumble/device.py +398 -182
- bumble/drivers/__init__.py +2 -2
- bumble/drivers/common.py +0 -2
- bumble/drivers/intel.py +37 -40
- bumble/drivers/rtk.py +28 -35
- bumble/gatt.py +4 -4
- bumble/gatt_adapters.py +4 -5
- bumble/gatt_client.py +26 -31
- bumble/gatt_server.py +7 -11
- bumble/hci.py +2648 -2909
- bumble/helpers.py +4 -5
- bumble/hfp.py +32 -37
- bumble/host.py +104 -35
- bumble/keys.py +5 -5
- bumble/l2cap.py +312 -409
- bumble/link.py +16 -280
- bumble/logging.py +65 -0
- bumble/pairing.py +23 -20
- bumble/pandora/__init__.py +2 -2
- bumble/pandora/config.py +2 -2
- bumble/pandora/device.py +6 -6
- bumble/pandora/host.py +27 -28
- bumble/pandora/l2cap.py +2 -2
- bumble/pandora/security.py +6 -6
- bumble/pandora/utils.py +3 -3
- bumble/profiles/ams.py +404 -0
- bumble/profiles/ascs.py +142 -131
- bumble/profiles/asha.py +2 -2
- bumble/profiles/bap.py +3 -4
- bumble/profiles/csip.py +2 -2
- bumble/profiles/device_information_service.py +2 -2
- bumble/profiles/gap.py +2 -2
- bumble/profiles/hap.py +34 -33
- bumble/profiles/le_audio.py +4 -4
- bumble/profiles/mcp.py +4 -4
- bumble/profiles/vcs.py +3 -5
- bumble/rfcomm.py +10 -10
- bumble/rtp.py +1 -2
- bumble/sdp.py +2 -2
- bumble/smp.py +62 -63
- bumble/tools/intel_util.py +3 -2
- bumble/tools/rtk_util.py +6 -5
- bumble/transport/__init__.py +2 -16
- bumble/transport/android_netsim.py +5 -5
- bumble/transport/common.py +4 -4
- bumble/transport/pyusb.py +2 -2
- bumble/utils.py +2 -5
- bumble/vendor/android/hci.py +118 -200
- bumble/vendor/zephyr/hci.py +32 -27
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/METADATA +4 -3
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/RECORD +89 -90
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/WHEEL +1 -1
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/entry_points.txt +0 -1
- bumble/apps/link_relay/__init__.py +0 -0
- bumble/apps/link_relay/link_relay.py +0 -289
- bumble/apps/link_relay/logging.yml +0 -21
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.212.dist-info → bumble-0.0.214.dist-info}/top_level.txt +0 -0
bumble/avctp.py
CHANGED
|
@@ -19,7 +19,7 @@ from __future__ import annotations
|
|
|
19
19
|
from enum import IntEnum
|
|
20
20
|
import logging
|
|
21
21
|
import struct
|
|
22
|
-
from typing import Callable, cast,
|
|
22
|
+
from typing import Callable, cast, Optional
|
|
23
23
|
|
|
24
24
|
from bumble.colors import color
|
|
25
25
|
from bumble import avc
|
|
@@ -146,9 +146,9 @@ class MessageAssembler:
|
|
|
146
146
|
# -----------------------------------------------------------------------------
|
|
147
147
|
class Protocol:
|
|
148
148
|
CommandHandler = Callable[[int, avc.CommandFrame], None]
|
|
149
|
-
command_handlers:
|
|
149
|
+
command_handlers: dict[int, CommandHandler] # Command handlers, by PID
|
|
150
150
|
ResponseHandler = Callable[[int, Optional[avc.ResponseFrame]], None]
|
|
151
|
-
response_handlers:
|
|
151
|
+
response_handlers: dict[int, ResponseHandler] # Response handlers, by PID
|
|
152
152
|
next_transaction_label: int
|
|
153
153
|
message_assembler: MessageAssembler
|
|
154
154
|
|
bumble/avdtp.py
CHANGED
|
@@ -24,12 +24,8 @@ import warnings
|
|
|
24
24
|
from typing import (
|
|
25
25
|
Any,
|
|
26
26
|
Awaitable,
|
|
27
|
-
Dict,
|
|
28
|
-
Type,
|
|
29
|
-
Tuple,
|
|
30
27
|
Optional,
|
|
31
28
|
Callable,
|
|
32
|
-
List,
|
|
33
29
|
AsyncGenerator,
|
|
34
30
|
Iterable,
|
|
35
31
|
Union,
|
|
@@ -227,7 +223,7 @@ AVDTP_STATE_NAMES = {
|
|
|
227
223
|
# -----------------------------------------------------------------------------
|
|
228
224
|
async def find_avdtp_service_with_sdp_client(
|
|
229
225
|
sdp_client: sdp.Client,
|
|
230
|
-
) -> Optional[
|
|
226
|
+
) -> Optional[tuple[int, int]]:
|
|
231
227
|
'''
|
|
232
228
|
Find an AVDTP service, using a connected SDP client, and return its version,
|
|
233
229
|
or None if none is found
|
|
@@ -257,7 +253,7 @@ async def find_avdtp_service_with_sdp_client(
|
|
|
257
253
|
# -----------------------------------------------------------------------------
|
|
258
254
|
async def find_avdtp_service_with_connection(
|
|
259
255
|
connection: device.Connection,
|
|
260
|
-
) -> Optional[
|
|
256
|
+
) -> Optional[tuple[int, int]]:
|
|
261
257
|
'''
|
|
262
258
|
Find an AVDTP service, for a connection, and return its version,
|
|
263
259
|
or None if none is found
|
|
@@ -451,7 +447,7 @@ class ServiceCapabilities:
|
|
|
451
447
|
service_category: int, service_capabilities_bytes: bytes
|
|
452
448
|
) -> ServiceCapabilities:
|
|
453
449
|
# Select the appropriate subclass
|
|
454
|
-
cls:
|
|
450
|
+
cls: type[ServiceCapabilities]
|
|
455
451
|
if service_category == AVDTP_MEDIA_CODEC_SERVICE_CATEGORY:
|
|
456
452
|
cls = MediaCodecCapabilities
|
|
457
453
|
else:
|
|
@@ -466,7 +462,7 @@ class ServiceCapabilities:
|
|
|
466
462
|
return instance
|
|
467
463
|
|
|
468
464
|
@staticmethod
|
|
469
|
-
def parse_capabilities(payload: bytes) ->
|
|
465
|
+
def parse_capabilities(payload: bytes) -> list[ServiceCapabilities]:
|
|
470
466
|
capabilities = []
|
|
471
467
|
while payload:
|
|
472
468
|
service_category = payload[0]
|
|
@@ -499,7 +495,7 @@ class ServiceCapabilities:
|
|
|
499
495
|
self.service_category = service_category
|
|
500
496
|
self.service_capabilities_bytes = service_capabilities_bytes
|
|
501
497
|
|
|
502
|
-
def to_string(self, details: Optional[
|
|
498
|
+
def to_string(self, details: Optional[list[str]] = None) -> str:
|
|
503
499
|
attributes = ','.join(
|
|
504
500
|
[name_or_number(AVDTP_SERVICE_CATEGORY_NAMES, self.service_category)]
|
|
505
501
|
+ (details or [])
|
|
@@ -612,7 +608,7 @@ class Message: # pylint:disable=attribute-defined-outside-init
|
|
|
612
608
|
RESPONSE_REJECT = 3
|
|
613
609
|
|
|
614
610
|
# Subclasses, by signal identifier and message type
|
|
615
|
-
subclasses:
|
|
611
|
+
subclasses: dict[int, dict[int, type[Message]]] = {}
|
|
616
612
|
message_type: MessageType
|
|
617
613
|
signal_identifier: int
|
|
618
614
|
|
|
@@ -757,7 +753,7 @@ class Discover_Response(Message):
|
|
|
757
753
|
See Bluetooth AVDTP spec - 8.6.2 Stream End Point Discovery Response
|
|
758
754
|
'''
|
|
759
755
|
|
|
760
|
-
endpoints:
|
|
756
|
+
endpoints: list[EndPointInfo]
|
|
761
757
|
|
|
762
758
|
def init_from_payload(self):
|
|
763
759
|
self.endpoints = []
|
|
@@ -1202,10 +1198,10 @@ class DelayReport_Reject(Simple_Reject):
|
|
|
1202
1198
|
|
|
1203
1199
|
# -----------------------------------------------------------------------------
|
|
1204
1200
|
class Protocol(utils.EventEmitter):
|
|
1205
|
-
local_endpoints:
|
|
1206
|
-
remote_endpoints:
|
|
1207
|
-
streams:
|
|
1208
|
-
transaction_results:
|
|
1201
|
+
local_endpoints: list[LocalStreamEndPoint]
|
|
1202
|
+
remote_endpoints: dict[int, DiscoveredStreamEndPoint]
|
|
1203
|
+
streams: dict[int, Stream]
|
|
1204
|
+
transaction_results: list[Optional[asyncio.Future[Message]]]
|
|
1209
1205
|
channel_connector: Callable[[], Awaitable[l2cap.ClassicChannel]]
|
|
1210
1206
|
|
|
1211
1207
|
EVENT_OPEN = "open"
|
|
@@ -1223,7 +1219,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1223
1219
|
|
|
1224
1220
|
@staticmethod
|
|
1225
1221
|
async def connect(
|
|
1226
|
-
connection: device.Connection, version:
|
|
1222
|
+
connection: device.Connection, version: tuple[int, int] = (1, 3)
|
|
1227
1223
|
) -> Protocol:
|
|
1228
1224
|
channel = await connection.create_l2cap_channel(
|
|
1229
1225
|
spec=l2cap.ClassicChannelSpec(psm=AVDTP_PSM)
|
|
@@ -1233,7 +1229,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1233
1229
|
return protocol
|
|
1234
1230
|
|
|
1235
1231
|
def __init__(
|
|
1236
|
-
self, l2cap_channel: l2cap.ClassicChannel, version:
|
|
1232
|
+
self, l2cap_channel: l2cap.ClassicChannel, version: tuple[int, int] = (1, 3)
|
|
1237
1233
|
) -> None:
|
|
1238
1234
|
super().__init__()
|
|
1239
1235
|
self.l2cap_channel = l2cap_channel
|
|
@@ -1502,7 +1498,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1502
1498
|
|
|
1503
1499
|
return response
|
|
1504
1500
|
|
|
1505
|
-
async def start_transaction(self) ->
|
|
1501
|
+
async def start_transaction(self) -> tuple[int, asyncio.Future[Message]]:
|
|
1506
1502
|
# Wait until we can start a new transaction
|
|
1507
1503
|
await self.transaction_semaphore.acquire()
|
|
1508
1504
|
|
|
@@ -1703,7 +1699,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1703
1699
|
|
|
1704
1700
|
# -----------------------------------------------------------------------------
|
|
1705
1701
|
class Listener(utils.EventEmitter):
|
|
1706
|
-
servers:
|
|
1702
|
+
servers: dict[int, Protocol]
|
|
1707
1703
|
|
|
1708
1704
|
EVENT_CONNECTION = "connection"
|
|
1709
1705
|
|
|
@@ -1735,7 +1731,7 @@ class Listener(utils.EventEmitter):
|
|
|
1735
1731
|
|
|
1736
1732
|
@classmethod
|
|
1737
1733
|
def for_device(
|
|
1738
|
-
cls, device: device.Device, version:
|
|
1734
|
+
cls, device: device.Device, version: tuple[int, int] = (1, 3)
|
|
1739
1735
|
) -> Listener:
|
|
1740
1736
|
listener = Listener(registrar=None, version=version)
|
|
1741
1737
|
l2cap_server = device.create_l2cap_server(
|
bumble/avrcp.py
CHANGED
|
@@ -26,14 +26,11 @@ from typing import (
|
|
|
26
26
|
Awaitable,
|
|
27
27
|
Callable,
|
|
28
28
|
cast,
|
|
29
|
-
Dict,
|
|
30
29
|
Iterable,
|
|
31
30
|
List,
|
|
32
31
|
Optional,
|
|
33
32
|
Sequence,
|
|
34
33
|
SupportsBytes,
|
|
35
|
-
Tuple,
|
|
36
|
-
Type,
|
|
37
34
|
TypeVar,
|
|
38
35
|
Union,
|
|
39
36
|
)
|
|
@@ -53,19 +50,10 @@ from bumble.sdp import (
|
|
|
53
50
|
ServiceAttribute,
|
|
54
51
|
)
|
|
55
52
|
from bumble import utils
|
|
56
|
-
from bumble
|
|
57
|
-
InvalidArgumentError,
|
|
58
|
-
ProtocolError,
|
|
59
|
-
BT_L2CAP_PROTOCOL_ID,
|
|
60
|
-
BT_AVCTP_PROTOCOL_ID,
|
|
61
|
-
BT_AV_REMOTE_CONTROL_SERVICE,
|
|
62
|
-
BT_AV_REMOTE_CONTROL_CONTROLLER_SERVICE,
|
|
63
|
-
BT_AV_REMOTE_CONTROL_TARGET_SERVICE,
|
|
64
|
-
)
|
|
53
|
+
from bumble import core
|
|
65
54
|
from bumble import l2cap
|
|
66
55
|
from bumble import avc
|
|
67
56
|
from bumble import avctp
|
|
68
|
-
from bumble import utils
|
|
69
57
|
|
|
70
58
|
|
|
71
59
|
# -----------------------------------------------------------------------------
|
|
@@ -84,10 +72,10 @@ AVRCP_BLUETOOTH_SIG_COMPANY_ID = 0x001958
|
|
|
84
72
|
# -----------------------------------------------------------------------------
|
|
85
73
|
def make_controller_service_sdp_records(
|
|
86
74
|
service_record_handle: int,
|
|
87
|
-
avctp_version:
|
|
88
|
-
avrcp_version:
|
|
75
|
+
avctp_version: tuple[int, int] = (1, 4),
|
|
76
|
+
avrcp_version: tuple[int, int] = (1, 6),
|
|
89
77
|
supported_features: int = 1,
|
|
90
|
-
) ->
|
|
78
|
+
) -> list[ServiceAttribute]:
|
|
91
79
|
# TODO: support a way to compute the supported features from a feature list
|
|
92
80
|
avctp_version_int = avctp_version[0] << 8 | avctp_version[1]
|
|
93
81
|
avrcp_version_int = avrcp_version[0] << 8 | avrcp_version[1]
|
|
@@ -105,8 +93,8 @@ def make_controller_service_sdp_records(
|
|
|
105
93
|
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
|
|
106
94
|
DataElement.sequence(
|
|
107
95
|
[
|
|
108
|
-
DataElement.uuid(BT_AV_REMOTE_CONTROL_SERVICE),
|
|
109
|
-
DataElement.uuid(BT_AV_REMOTE_CONTROL_CONTROLLER_SERVICE),
|
|
96
|
+
DataElement.uuid(core.BT_AV_REMOTE_CONTROL_SERVICE),
|
|
97
|
+
DataElement.uuid(core.BT_AV_REMOTE_CONTROL_CONTROLLER_SERVICE),
|
|
110
98
|
]
|
|
111
99
|
),
|
|
112
100
|
),
|
|
@@ -116,13 +104,13 @@ def make_controller_service_sdp_records(
|
|
|
116
104
|
[
|
|
117
105
|
DataElement.sequence(
|
|
118
106
|
[
|
|
119
|
-
DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
|
|
107
|
+
DataElement.uuid(core.BT_L2CAP_PROTOCOL_ID),
|
|
120
108
|
DataElement.unsigned_integer_16(avctp.AVCTP_PSM),
|
|
121
109
|
]
|
|
122
110
|
),
|
|
123
111
|
DataElement.sequence(
|
|
124
112
|
[
|
|
125
|
-
DataElement.uuid(BT_AVCTP_PROTOCOL_ID),
|
|
113
|
+
DataElement.uuid(core.BT_AVCTP_PROTOCOL_ID),
|
|
126
114
|
DataElement.unsigned_integer_16(avctp_version_int),
|
|
127
115
|
]
|
|
128
116
|
),
|
|
@@ -135,7 +123,7 @@ def make_controller_service_sdp_records(
|
|
|
135
123
|
[
|
|
136
124
|
DataElement.sequence(
|
|
137
125
|
[
|
|
138
|
-
DataElement.uuid(BT_AV_REMOTE_CONTROL_SERVICE),
|
|
126
|
+
DataElement.uuid(core.BT_AV_REMOTE_CONTROL_SERVICE),
|
|
139
127
|
DataElement.unsigned_integer_16(avrcp_version_int),
|
|
140
128
|
]
|
|
141
129
|
),
|
|
@@ -152,10 +140,10 @@ def make_controller_service_sdp_records(
|
|
|
152
140
|
# -----------------------------------------------------------------------------
|
|
153
141
|
def make_target_service_sdp_records(
|
|
154
142
|
service_record_handle: int,
|
|
155
|
-
avctp_version:
|
|
156
|
-
avrcp_version:
|
|
143
|
+
avctp_version: tuple[int, int] = (1, 4),
|
|
144
|
+
avrcp_version: tuple[int, int] = (1, 6),
|
|
157
145
|
supported_features: int = 0x23,
|
|
158
|
-
) ->
|
|
146
|
+
) -> list[ServiceAttribute]:
|
|
159
147
|
# TODO: support a way to compute the supported features from a feature list
|
|
160
148
|
avctp_version_int = avctp_version[0] << 8 | avctp_version[1]
|
|
161
149
|
avrcp_version_int = avrcp_version[0] << 8 | avrcp_version[1]
|
|
@@ -173,7 +161,7 @@ def make_target_service_sdp_records(
|
|
|
173
161
|
SDP_SERVICE_CLASS_ID_LIST_ATTRIBUTE_ID,
|
|
174
162
|
DataElement.sequence(
|
|
175
163
|
[
|
|
176
|
-
DataElement.uuid(BT_AV_REMOTE_CONTROL_TARGET_SERVICE),
|
|
164
|
+
DataElement.uuid(core.BT_AV_REMOTE_CONTROL_TARGET_SERVICE),
|
|
177
165
|
]
|
|
178
166
|
),
|
|
179
167
|
),
|
|
@@ -183,13 +171,13 @@ def make_target_service_sdp_records(
|
|
|
183
171
|
[
|
|
184
172
|
DataElement.sequence(
|
|
185
173
|
[
|
|
186
|
-
DataElement.uuid(BT_L2CAP_PROTOCOL_ID),
|
|
174
|
+
DataElement.uuid(core.BT_L2CAP_PROTOCOL_ID),
|
|
187
175
|
DataElement.unsigned_integer_16(avctp.AVCTP_PSM),
|
|
188
176
|
]
|
|
189
177
|
),
|
|
190
178
|
DataElement.sequence(
|
|
191
179
|
[
|
|
192
|
-
DataElement.uuid(BT_AVCTP_PROTOCOL_ID),
|
|
180
|
+
DataElement.uuid(core.BT_AVCTP_PROTOCOL_ID),
|
|
193
181
|
DataElement.unsigned_integer_16(avctp_version_int),
|
|
194
182
|
]
|
|
195
183
|
),
|
|
@@ -202,7 +190,7 @@ def make_target_service_sdp_records(
|
|
|
202
190
|
[
|
|
203
191
|
DataElement.sequence(
|
|
204
192
|
[
|
|
205
|
-
DataElement.uuid(BT_AV_REMOTE_CONTROL_SERVICE),
|
|
193
|
+
DataElement.uuid(core.BT_AV_REMOTE_CONTROL_SERVICE),
|
|
206
194
|
DataElement.unsigned_integer_16(avrcp_version_int),
|
|
207
195
|
]
|
|
208
196
|
),
|
|
@@ -291,7 +279,7 @@ class Command:
|
|
|
291
279
|
pdu_id: Protocol.PduId
|
|
292
280
|
parameter: bytes
|
|
293
281
|
|
|
294
|
-
def to_string(self, properties:
|
|
282
|
+
def to_string(self, properties: dict[str, str]) -> str:
|
|
295
283
|
properties_str = ",".join(
|
|
296
284
|
[f"{name}={value}" for name, value in properties.items()]
|
|
297
285
|
)
|
|
@@ -337,7 +325,7 @@ class GetPlayStatusCommand(Command):
|
|
|
337
325
|
# -----------------------------------------------------------------------------
|
|
338
326
|
class GetElementAttributesCommand(Command):
|
|
339
327
|
identifier: int
|
|
340
|
-
attribute_ids:
|
|
328
|
+
attribute_ids: list[MediaAttributeId]
|
|
341
329
|
|
|
342
330
|
@classmethod
|
|
343
331
|
def from_bytes(cls, pdu: bytes) -> GetElementAttributesCommand:
|
|
@@ -409,7 +397,7 @@ class Response:
|
|
|
409
397
|
pdu_id: Protocol.PduId
|
|
410
398
|
parameter: bytes
|
|
411
399
|
|
|
412
|
-
def to_string(self, properties:
|
|
400
|
+
def to_string(self, properties: dict[str, str]) -> str:
|
|
413
401
|
properties_str = ",".join(
|
|
414
402
|
[f"{name}={value}" for name, value in properties.items()]
|
|
415
403
|
)
|
|
@@ -454,7 +442,7 @@ class NotImplementedResponse(Response):
|
|
|
454
442
|
# -----------------------------------------------------------------------------
|
|
455
443
|
class GetCapabilitiesResponse(Response):
|
|
456
444
|
capability_id: GetCapabilitiesCommand.CapabilityId
|
|
457
|
-
capabilities:
|
|
445
|
+
capabilities: list[Union[SupportsBytes, bytes]]
|
|
458
446
|
|
|
459
447
|
@classmethod
|
|
460
448
|
def from_bytes(cls, pdu: bytes) -> GetCapabilitiesResponse:
|
|
@@ -467,7 +455,7 @@ class GetCapabilitiesResponse(Response):
|
|
|
467
455
|
capability_id = GetCapabilitiesCommand.CapabilityId(pdu[0])
|
|
468
456
|
capability_count = pdu[1]
|
|
469
457
|
|
|
470
|
-
capabilities:
|
|
458
|
+
capabilities: list[Union[SupportsBytes, bytes]]
|
|
471
459
|
if capability_id == GetCapabilitiesCommand.CapabilityId.EVENTS_SUPPORTED:
|
|
472
460
|
capabilities = [EventId(pdu[2 + x]) for x in range(capability_count)]
|
|
473
461
|
else:
|
|
@@ -540,13 +528,13 @@ class GetPlayStatusResponse(Response):
|
|
|
540
528
|
|
|
541
529
|
# -----------------------------------------------------------------------------
|
|
542
530
|
class GetElementAttributesResponse(Response):
|
|
543
|
-
attributes:
|
|
531
|
+
attributes: list[MediaAttribute]
|
|
544
532
|
|
|
545
533
|
@classmethod
|
|
546
534
|
def from_bytes(cls, pdu: bytes) -> GetElementAttributesResponse:
|
|
547
535
|
num_attributes = pdu[0]
|
|
548
536
|
offset = 1
|
|
549
|
-
attributes:
|
|
537
|
+
attributes: list[MediaAttribute] = []
|
|
550
538
|
for _ in range(num_attributes):
|
|
551
539
|
(
|
|
552
540
|
attribute_id_int,
|
|
@@ -817,7 +805,7 @@ class PlayerApplicationSettingChangedEvent(Event):
|
|
|
817
805
|
attribute_id: ApplicationSetting.AttributeId
|
|
818
806
|
value_id: utils.OpenIntEnum
|
|
819
807
|
|
|
820
|
-
player_application_settings:
|
|
808
|
+
player_application_settings: list[Setting]
|
|
821
809
|
|
|
822
810
|
@classmethod
|
|
823
811
|
def from_bytes(cls, pdu: bytes) -> PlayerApplicationSettingChangedEvent:
|
|
@@ -939,7 +927,7 @@ class VolumeChangedEvent(Event):
|
|
|
939
927
|
|
|
940
928
|
|
|
941
929
|
# -----------------------------------------------------------------------------
|
|
942
|
-
EVENT_SUBCLASSES:
|
|
930
|
+
EVENT_SUBCLASSES: dict[EventId, type[Event]] = {
|
|
943
931
|
EventId.PLAYBACK_STATUS_CHANGED: PlaybackStatusChangedEvent,
|
|
944
932
|
EventId.PLAYBACK_POS_CHANGED: PlaybackPositionChangedEvent,
|
|
945
933
|
EventId.TRACK_CHANGED: TrackChangedEvent,
|
|
@@ -967,14 +955,14 @@ class Delegate:
|
|
|
967
955
|
def __init__(self, status_code: Protocol.StatusCode) -> None:
|
|
968
956
|
self.status_code = status_code
|
|
969
957
|
|
|
970
|
-
supported_events:
|
|
958
|
+
supported_events: list[EventId]
|
|
971
959
|
volume: int
|
|
972
960
|
|
|
973
961
|
def __init__(self, supported_events: Iterable[EventId] = ()) -> None:
|
|
974
962
|
self.supported_events = list(supported_events)
|
|
975
963
|
self.volume = 0
|
|
976
964
|
|
|
977
|
-
async def get_supported_events(self) ->
|
|
965
|
+
async def get_supported_events(self) -> list[EventId]:
|
|
978
966
|
return self.supported_events
|
|
979
967
|
|
|
980
968
|
async def set_absolute_volume(self, volume: int) -> None:
|
|
@@ -1124,12 +1112,12 @@ class Protocol(utils.EventEmitter):
|
|
|
1124
1112
|
receive_response_state: Optional[ReceiveResponseState]
|
|
1125
1113
|
avctp_protocol: Optional[avctp.Protocol]
|
|
1126
1114
|
free_commands: asyncio.Queue
|
|
1127
|
-
pending_commands:
|
|
1128
|
-
notification_listeners:
|
|
1115
|
+
pending_commands: dict[int, PendingCommand] # Pending commands, by label
|
|
1116
|
+
notification_listeners: dict[EventId, NotificationListener]
|
|
1129
1117
|
|
|
1130
1118
|
@staticmethod
|
|
1131
1119
|
def _check_vendor_dependent_frame(
|
|
1132
|
-
frame: Union[avc.VendorDependentCommandFrame, avc.VendorDependentResponseFrame]
|
|
1120
|
+
frame: Union[avc.VendorDependentCommandFrame, avc.VendorDependentResponseFrame],
|
|
1133
1121
|
) -> bool:
|
|
1134
1122
|
if frame.company_id != AVRCP_BLUETOOTH_SIG_COMPANY_ID:
|
|
1135
1123
|
logger.debug("unsupported company id, ignoring")
|
|
@@ -1190,7 +1178,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1190
1178
|
|
|
1191
1179
|
@staticmethod
|
|
1192
1180
|
def _check_response(
|
|
1193
|
-
response_context: ResponseContext, expected_type:
|
|
1181
|
+
response_context: ResponseContext, expected_type: type[_R]
|
|
1194
1182
|
) -> _R:
|
|
1195
1183
|
if isinstance(response_context, Protocol.FinalResponse):
|
|
1196
1184
|
if (
|
|
@@ -1211,7 +1199,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1211
1199
|
def _delegate_command(
|
|
1212
1200
|
self, transaction_label: int, command: Command, method: Awaitable
|
|
1213
1201
|
) -> None:
|
|
1214
|
-
async def call():
|
|
1202
|
+
async def call() -> None:
|
|
1215
1203
|
try:
|
|
1216
1204
|
await method
|
|
1217
1205
|
except Delegate.Error as error:
|
|
@@ -1230,7 +1218,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1230
1218
|
|
|
1231
1219
|
utils.AsyncRunner.spawn(call())
|
|
1232
1220
|
|
|
1233
|
-
async def get_supported_events(self) ->
|
|
1221
|
+
async def get_supported_events(self) -> list[EventId]:
|
|
1234
1222
|
"""Get the list of events supported by the connected peer."""
|
|
1235
1223
|
response_context = await self.send_avrcp_command(
|
|
1236
1224
|
avc.CommandFrame.CommandType.STATUS,
|
|
@@ -1253,7 +1241,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1253
1241
|
|
|
1254
1242
|
async def get_element_attributes(
|
|
1255
1243
|
self, element_identifier: int, attribute_ids: Sequence[MediaAttributeId]
|
|
1256
|
-
) ->
|
|
1244
|
+
) -> list[MediaAttribute]:
|
|
1257
1245
|
"""Get element attributes from the connected peer."""
|
|
1258
1246
|
response_context = await self.send_avrcp_command(
|
|
1259
1247
|
avc.CommandFrame.CommandType.STATUS,
|
|
@@ -1335,7 +1323,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1335
1323
|
|
|
1336
1324
|
async def monitor_player_application_settings(
|
|
1337
1325
|
self,
|
|
1338
|
-
) -> AsyncIterator[
|
|
1326
|
+
) -> AsyncIterator[list[PlayerApplicationSettingChangedEvent.Setting]]:
|
|
1339
1327
|
"""Monitor Player Application Setting changes from the connected peer."""
|
|
1340
1328
|
async for event in self.monitor_events(
|
|
1341
1329
|
EventId.PLAYER_APPLICATION_SETTING_CHANGED, 0
|
|
@@ -1415,7 +1403,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1415
1403
|
def notify_track_changed(self, identifier: bytes) -> None:
|
|
1416
1404
|
"""Notify the connected peer of a Track change."""
|
|
1417
1405
|
if len(identifier) != 8:
|
|
1418
|
-
raise InvalidArgumentError("identifier must be 8 bytes")
|
|
1406
|
+
raise core.InvalidArgumentError("identifier must be 8 bytes")
|
|
1419
1407
|
self.notify_event(TrackChangedEvent(identifier))
|
|
1420
1408
|
|
|
1421
1409
|
def notify_playback_position_changed(self, position: int) -> None:
|
|
@@ -1682,7 +1670,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1682
1670
|
else:
|
|
1683
1671
|
logger.debug("unexpected PDU ID")
|
|
1684
1672
|
pending_command.response.set_exception(
|
|
1685
|
-
ProtocolError(
|
|
1673
|
+
core.ProtocolError(
|
|
1686
1674
|
error_code=None,
|
|
1687
1675
|
error_namespace="avrcp",
|
|
1688
1676
|
details="unexpected PDU ID",
|
|
@@ -1691,7 +1679,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1691
1679
|
else:
|
|
1692
1680
|
logger.debug("unexpected response code")
|
|
1693
1681
|
pending_command.response.set_exception(
|
|
1694
|
-
ProtocolError(
|
|
1682
|
+
core.ProtocolError(
|
|
1695
1683
|
error_code=None,
|
|
1696
1684
|
error_namespace="avrcp",
|
|
1697
1685
|
details="unexpected response code",
|
|
@@ -1869,12 +1857,12 @@ class Protocol(utils.EventEmitter):
|
|
|
1869
1857
|
) -> None:
|
|
1870
1858
|
logger.debug(f"<<< AVRCP command PDU: {command}")
|
|
1871
1859
|
|
|
1872
|
-
async def get_supported_events():
|
|
1860
|
+
async def get_supported_events() -> None:
|
|
1873
1861
|
if (
|
|
1874
1862
|
command.capability_id
|
|
1875
1863
|
!= GetCapabilitiesCommand.CapabilityId.EVENTS_SUPPORTED
|
|
1876
1864
|
):
|
|
1877
|
-
raise
|
|
1865
|
+
raise core.InvalidArgumentError()
|
|
1878
1866
|
|
|
1879
1867
|
supported_events = await self.delegate.get_supported_events()
|
|
1880
1868
|
self.send_avrcp_response(
|
|
@@ -1890,7 +1878,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1890
1878
|
) -> None:
|
|
1891
1879
|
logger.debug(f"<<< AVRCP command PDU: {command}")
|
|
1892
1880
|
|
|
1893
|
-
async def set_absolute_volume():
|
|
1881
|
+
async def set_absolute_volume() -> None:
|
|
1894
1882
|
await self.delegate.set_absolute_volume(command.volume)
|
|
1895
1883
|
effective_volume = await self.delegate.get_absolute_volume()
|
|
1896
1884
|
self.send_avrcp_response(
|
|
@@ -1906,7 +1894,7 @@ class Protocol(utils.EventEmitter):
|
|
|
1906
1894
|
) -> None:
|
|
1907
1895
|
logger.debug(f"<<< AVRCP command PDU: {command}")
|
|
1908
1896
|
|
|
1909
|
-
async def register_notification():
|
|
1897
|
+
async def register_notification() -> None:
|
|
1910
1898
|
# Check if the event is supported.
|
|
1911
1899
|
supported_events = await self.delegate.get_supported_events()
|
|
1912
1900
|
if command.event_id not in supported_events:
|
bumble/colors.py
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
14
14
|
|
|
15
15
|
from functools import partial
|
|
16
|
-
from typing import
|
|
16
|
+
from typing import Optional, Union
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class ColorError(ValueError):
|
|
@@ -65,7 +65,7 @@ def color(
|
|
|
65
65
|
bg: Optional[ColorSpec] = None,
|
|
66
66
|
style: Optional[str] = None,
|
|
67
67
|
) -> str:
|
|
68
|
-
codes:
|
|
68
|
+
codes: list[ColorSpec] = []
|
|
69
69
|
|
|
70
70
|
if fg:
|
|
71
71
|
codes.append(_color_code(fg, 30))
|