bumble 0.0.214__py3-none-any.whl → 0.0.216__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 +16 -3
- bumble/a2dp.py +15 -16
- bumble/apps/auracast.py +13 -38
- bumble/apps/bench.py +9 -10
- bumble/apps/ble_rpa_tool.py +1 -0
- bumble/apps/console.py +22 -25
- bumble/apps/controller_info.py +19 -19
- bumble/apps/controller_loopback.py +2 -2
- bumble/apps/controllers.py +1 -1
- bumble/apps/device_info.py +3 -3
- bumble/apps/gatt_dump.py +1 -1
- bumble/apps/gg_bridge.py +5 -6
- bumble/apps/hci_bridge.py +3 -3
- bumble/apps/l2cap_bridge.py +3 -3
- bumble/apps/lea_unicast/app.py +15 -25
- bumble/apps/pair.py +30 -43
- bumble/apps/pandora_server.py +5 -4
- bumble/apps/player/player.py +19 -22
- bumble/apps/rfcomm_bridge.py +3 -8
- bumble/apps/scan.py +16 -6
- bumble/apps/show.py +3 -4
- bumble/apps/speaker/speaker.py +22 -22
- bumble/apps/unbond.py +2 -1
- bumble/apps/usb_probe.py +1 -2
- bumble/att.py +241 -246
- bumble/audio/io.py +5 -9
- bumble/avc.py +2 -2
- bumble/avctp.py +6 -7
- bumble/avdtp.py +19 -22
- bumble/avrcp.py +1096 -588
- bumble/codecs.py +2 -0
- bumble/controller.py +52 -13
- bumble/core.py +567 -248
- bumble/crypto/__init__.py +2 -2
- bumble/crypto/builtin.py +1 -1
- bumble/crypto/cryptography.py +2 -4
- bumble/data_types.py +1025 -0
- bumble/device.py +318 -279
- bumble/drivers/__init__.py +3 -2
- bumble/drivers/intel.py +3 -4
- bumble/drivers/rtk.py +26 -9
- bumble/gap.py +4 -4
- bumble/gatt.py +3 -2
- bumble/gatt_adapters.py +3 -11
- bumble/gatt_client.py +69 -81
- bumble/gatt_server.py +124 -124
- bumble/hci.py +67 -18
- bumble/helpers.py +19 -26
- bumble/hfp.py +10 -21
- bumble/hid.py +22 -16
- bumble/host.py +181 -103
- bumble/keys.py +5 -3
- bumble/l2cap.py +121 -74
- bumble/link.py +8 -9
- bumble/pairing.py +7 -6
- bumble/pandora/__init__.py +8 -7
- bumble/pandora/config.py +3 -1
- bumble/pandora/device.py +3 -2
- bumble/pandora/host.py +38 -36
- bumble/pandora/l2cap.py +22 -21
- bumble/pandora/security.py +15 -15
- bumble/pandora/utils.py +5 -3
- bumble/profiles/aics.py +11 -11
- bumble/profiles/ams.py +7 -8
- bumble/profiles/ancs.py +6 -7
- bumble/profiles/ascs.py +4 -9
- bumble/profiles/asha.py +8 -12
- bumble/profiles/bap.py +11 -23
- bumble/profiles/bass.py +2 -7
- bumble/profiles/battery_service.py +3 -4
- bumble/profiles/cap.py +1 -2
- bumble/profiles/csip.py +2 -6
- bumble/profiles/device_information_service.py +2 -2
- bumble/profiles/gap.py +4 -4
- bumble/profiles/gatt_service.py +1 -4
- bumble/profiles/gmap.py +5 -5
- bumble/profiles/hap.py +62 -59
- bumble/profiles/heart_rate_service.py +5 -4
- bumble/profiles/le_audio.py +3 -1
- bumble/profiles/mcp.py +3 -7
- bumble/profiles/pacs.py +3 -6
- bumble/profiles/pbp.py +2 -0
- bumble/profiles/tmap.py +2 -3
- bumble/profiles/vcs.py +2 -8
- bumble/profiles/vocs.py +8 -8
- bumble/rfcomm.py +11 -14
- bumble/rtp.py +1 -0
- bumble/sdp.py +10 -8
- bumble/smp.py +142 -153
- bumble/snoop.py +5 -5
- bumble/tools/generate_company_id_list.py +1 -0
- bumble/tools/intel_fw_download.py +3 -3
- bumble/tools/intel_util.py +4 -4
- bumble/tools/rtk_fw_download.py +6 -3
- bumble/tools/rtk_util.py +24 -7
- bumble/transport/__init__.py +19 -15
- bumble/transport/android_emulator.py +8 -13
- bumble/transport/android_netsim.py +19 -18
- bumble/transport/common.py +12 -15
- bumble/transport/file.py +1 -1
- bumble/transport/hci_socket.py +4 -6
- bumble/transport/pty.py +5 -6
- bumble/transport/pyusb.py +7 -10
- bumble/transport/serial.py +2 -1
- bumble/transport/tcp_client.py +2 -2
- bumble/transport/tcp_server.py +11 -14
- bumble/transport/udp.py +3 -3
- bumble/transport/unix.py +67 -1
- bumble/transport/usb.py +6 -6
- bumble/transport/vhci.py +0 -1
- bumble/transport/ws_client.py +2 -1
- bumble/transport/ws_server.py +3 -2
- bumble/utils.py +20 -5
- bumble/vendor/android/hci.py +1 -2
- bumble/vendor/zephyr/hci.py +0 -1
- {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/METADATA +2 -1
- bumble-0.0.216.dist-info/RECORD +183 -0
- bumble-0.0.214.dist-info/RECORD +0 -182
- {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/WHEEL +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/entry_points.txt +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/licenses/LICENSE +0 -0
- {bumble-0.0.214.dist-info → bumble-0.0.216.dist-info}/top_level.txt +0 -0
bumble/profiles/ams.py
CHANGED
|
@@ -20,25 +20,24 @@ Apple Media Service (AMS).
|
|
|
20
20
|
# Imports
|
|
21
21
|
# -----------------------------------------------------------------------------
|
|
22
22
|
from __future__ import annotations
|
|
23
|
+
|
|
23
24
|
import asyncio
|
|
24
25
|
import dataclasses
|
|
25
26
|
import enum
|
|
26
27
|
import logging
|
|
27
|
-
from typing import
|
|
28
|
-
|
|
28
|
+
from typing import Iterable, Optional, Union
|
|
29
29
|
|
|
30
|
+
from bumble import utils
|
|
30
31
|
from bumble.device import Peer
|
|
31
32
|
from bumble.gatt import (
|
|
32
|
-
Characteristic,
|
|
33
|
-
GATT_AMS_SERVICE,
|
|
34
|
-
GATT_AMS_REMOTE_COMMAND_CHARACTERISTIC,
|
|
35
|
-
GATT_AMS_ENTITY_UPDATE_CHARACTERISTIC,
|
|
36
33
|
GATT_AMS_ENTITY_ATTRIBUTE_CHARACTERISTIC,
|
|
34
|
+
GATT_AMS_ENTITY_UPDATE_CHARACTERISTIC,
|
|
35
|
+
GATT_AMS_REMOTE_COMMAND_CHARACTERISTIC,
|
|
36
|
+
GATT_AMS_SERVICE,
|
|
37
|
+
Characteristic,
|
|
37
38
|
TemplateService,
|
|
38
39
|
)
|
|
39
40
|
from bumble.gatt_client import CharacteristicProxy, ProfileServiceProxy, ServiceProxy
|
|
40
|
-
from bumble import utils
|
|
41
|
-
|
|
42
41
|
|
|
43
42
|
# -----------------------------------------------------------------------------
|
|
44
43
|
# Logging
|
bumble/profiles/ancs.py
CHANGED
|
@@ -20,6 +20,7 @@ Apple Notification Center Service (ANCS).
|
|
|
20
20
|
# Imports
|
|
21
21
|
# -----------------------------------------------------------------------------
|
|
22
22
|
from __future__ import annotations
|
|
23
|
+
|
|
23
24
|
import asyncio
|
|
24
25
|
import dataclasses
|
|
25
26
|
import datetime
|
|
@@ -28,21 +29,19 @@ import logging
|
|
|
28
29
|
import struct
|
|
29
30
|
from typing import Optional, Sequence, Union
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
from bumble import utils
|
|
32
33
|
from bumble.att import ATT_Error
|
|
33
34
|
from bumble.device import Peer
|
|
34
35
|
from bumble.gatt import (
|
|
35
|
-
Characteristic,
|
|
36
|
-
GATT_ANCS_SERVICE,
|
|
37
|
-
GATT_ANCS_NOTIFICATION_SOURCE_CHARACTERISTIC,
|
|
38
36
|
GATT_ANCS_CONTROL_POINT_CHARACTERISTIC,
|
|
39
37
|
GATT_ANCS_DATA_SOURCE_CHARACTERISTIC,
|
|
38
|
+
GATT_ANCS_NOTIFICATION_SOURCE_CHARACTERISTIC,
|
|
39
|
+
GATT_ANCS_SERVICE,
|
|
40
|
+
Characteristic,
|
|
40
41
|
TemplateService,
|
|
41
42
|
)
|
|
42
|
-
from bumble.gatt_client import CharacteristicProxy, ProfileServiceProxy, ServiceProxy
|
|
43
43
|
from bumble.gatt_adapters import SerializableCharacteristicProxyAdapter
|
|
44
|
-
from bumble import
|
|
45
|
-
|
|
44
|
+
from bumble.gatt_client import CharacteristicProxy, ProfileServiceProxy, ServiceProxy
|
|
46
45
|
|
|
47
46
|
# -----------------------------------------------------------------------------
|
|
48
47
|
# Constants
|
bumble/profiles/ascs.py
CHANGED
|
@@ -18,22 +18,17 @@
|
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
-
from dataclasses import dataclass, field
|
|
22
21
|
import enum
|
|
23
22
|
import functools
|
|
24
23
|
import logging
|
|
25
24
|
import struct
|
|
26
|
-
from typing import Any, Optional, Union, TypeVar
|
|
27
25
|
from collections.abc import Sequence
|
|
26
|
+
from dataclasses import dataclass, field
|
|
27
|
+
from typing import Any, Optional, TypeVar, Union
|
|
28
28
|
|
|
29
|
-
from bumble import utils
|
|
30
|
-
from bumble import colors
|
|
31
|
-
from bumble.profiles.bap import CodecSpecificConfiguration
|
|
29
|
+
from bumble import colors, device, gatt, gatt_client, hci, utils
|
|
32
30
|
from bumble.profiles import le_audio
|
|
33
|
-
from bumble import
|
|
34
|
-
from bumble import gatt
|
|
35
|
-
from bumble import gatt_client
|
|
36
|
-
from bumble import hci
|
|
31
|
+
from bumble.profiles.bap import CodecSpecificConfiguration
|
|
37
32
|
|
|
38
33
|
# -----------------------------------------------------------------------------
|
|
39
34
|
# Logging
|
bumble/profiles/asha.py
CHANGED
|
@@ -17,16 +17,13 @@
|
|
|
17
17
|
# Imports
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
import enum
|
|
20
|
-
import struct
|
|
21
20
|
import logging
|
|
22
|
-
|
|
21
|
+
import struct
|
|
22
|
+
from typing import Any, Callable, Optional, Union
|
|
23
23
|
|
|
24
|
-
from bumble import l2cap
|
|
25
|
-
from bumble import utils
|
|
26
|
-
from bumble import gatt
|
|
27
|
-
from bumble import gatt_client
|
|
24
|
+
from bumble import data_types, gatt, gatt_client, l2cap, utils
|
|
28
25
|
from bumble.core import AdvertisingData
|
|
29
|
-
from bumble.device import
|
|
26
|
+
from bumble.device import Connection, Device
|
|
30
27
|
|
|
31
28
|
# -----------------------------------------------------------------------------
|
|
32
29
|
# Logging
|
|
@@ -188,12 +185,11 @@ class AshaService(gatt.TemplateService):
|
|
|
188
185
|
return bytes(
|
|
189
186
|
AdvertisingData(
|
|
190
187
|
[
|
|
191
|
-
(
|
|
192
|
-
|
|
193
|
-
bytes(
|
|
194
|
-
+ bytes([self.protocol_version, self.capability])
|
|
188
|
+
data_types.ServiceData16BitUUID(
|
|
189
|
+
gatt.GATT_ASHA_SERVICE,
|
|
190
|
+
bytes([self.protocol_version, self.capability])
|
|
195
191
|
+ self.hisyncid[:4],
|
|
196
|
-
)
|
|
192
|
+
)
|
|
197
193
|
]
|
|
198
194
|
)
|
|
199
195
|
)
|
bumble/profiles/bap.py
CHANGED
|
@@ -18,21 +18,18 @@
|
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
-
from collections.abc import Sequence
|
|
22
21
|
import dataclasses
|
|
23
22
|
import enum
|
|
24
|
-
import struct
|
|
25
23
|
import functools
|
|
26
24
|
import logging
|
|
25
|
+
import struct
|
|
26
|
+
from collections.abc import Sequence
|
|
27
|
+
|
|
27
28
|
from typing_extensions import Self
|
|
28
29
|
|
|
29
|
-
from bumble import core
|
|
30
|
-
from bumble import hci
|
|
31
|
-
from bumble import gatt
|
|
32
|
-
from bumble import utils
|
|
30
|
+
from bumble import core, data_types, gatt, hci, utils
|
|
33
31
|
from bumble.profiles import le_audio
|
|
34
32
|
|
|
35
|
-
|
|
36
33
|
# -----------------------------------------------------------------------------
|
|
37
34
|
# Logging
|
|
38
35
|
# -----------------------------------------------------------------------------
|
|
@@ -260,11 +257,10 @@ class UnicastServerAdvertisingData:
|
|
|
260
257
|
return bytes(
|
|
261
258
|
core.AdvertisingData(
|
|
262
259
|
[
|
|
263
|
-
(
|
|
264
|
-
|
|
260
|
+
data_types.ServiceData16BitUUID(
|
|
261
|
+
gatt.GATT_AUDIO_STREAM_CONTROL_SERVICE,
|
|
265
262
|
struct.pack(
|
|
266
|
-
'<
|
|
267
|
-
bytes(gatt.GATT_AUDIO_STREAM_CONTROL_SERVICE),
|
|
263
|
+
'<BIB',
|
|
268
264
|
self.announcement_type,
|
|
269
265
|
self.available_audio_contexts,
|
|
270
266
|
len(self.metadata),
|
|
@@ -493,12 +489,8 @@ class BroadcastAudioAnnouncement:
|
|
|
493
489
|
return bytes(
|
|
494
490
|
core.AdvertisingData(
|
|
495
491
|
[
|
|
496
|
-
(
|
|
497
|
-
|
|
498
|
-
(
|
|
499
|
-
bytes(gatt.GATT_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE)
|
|
500
|
-
+ bytes(self)
|
|
501
|
-
),
|
|
492
|
+
data_types.ServiceData16BitUUID(
|
|
493
|
+
gatt.GATT_BROADCAST_AUDIO_ANNOUNCEMENT_SERVICE, bytes(self)
|
|
502
494
|
)
|
|
503
495
|
]
|
|
504
496
|
)
|
|
@@ -610,12 +602,8 @@ class BasicAudioAnnouncement:
|
|
|
610
602
|
return bytes(
|
|
611
603
|
core.AdvertisingData(
|
|
612
604
|
[
|
|
613
|
-
(
|
|
614
|
-
|
|
615
|
-
(
|
|
616
|
-
bytes(gatt.GATT_BASIC_AUDIO_ANNOUNCEMENT_SERVICE)
|
|
617
|
-
+ bytes(self)
|
|
618
|
-
),
|
|
605
|
+
data_types.ServiceData16BitUUID(
|
|
606
|
+
gatt.GATT_BASIC_AUDIO_ANNOUNCEMENT_SERVICE, bytes(self)
|
|
619
607
|
)
|
|
620
608
|
]
|
|
621
609
|
)
|
bumble/profiles/bass.py
CHANGED
|
@@ -17,18 +17,13 @@
|
|
|
17
17
|
# Imports
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
from __future__ import annotations
|
|
20
|
+
|
|
20
21
|
import dataclasses
|
|
21
22
|
import logging
|
|
22
23
|
import struct
|
|
23
24
|
from typing import ClassVar, Optional, Sequence
|
|
24
25
|
|
|
25
|
-
from bumble import core
|
|
26
|
-
from bumble import device
|
|
27
|
-
from bumble import gatt
|
|
28
|
-
from bumble import gatt_adapters
|
|
29
|
-
from bumble import gatt_client
|
|
30
|
-
from bumble import hci
|
|
31
|
-
from bumble import utils
|
|
26
|
+
from bumble import core, device, gatt, gatt_adapters, gatt_client, hci, utils
|
|
32
27
|
|
|
33
28
|
# -----------------------------------------------------------------------------
|
|
34
29
|
# Logging
|
|
@@ -18,19 +18,18 @@
|
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
from typing import Optional
|
|
20
20
|
|
|
21
|
-
from bumble.gatt_client import ProfileServiceProxy
|
|
22
21
|
from bumble.gatt import (
|
|
23
|
-
GATT_BATTERY_SERVICE,
|
|
24
22
|
GATT_BATTERY_LEVEL_CHARACTERISTIC,
|
|
25
|
-
|
|
23
|
+
GATT_BATTERY_SERVICE,
|
|
26
24
|
Characteristic,
|
|
27
25
|
CharacteristicValue,
|
|
26
|
+
TemplateService,
|
|
28
27
|
)
|
|
29
|
-
from bumble.gatt_client import CharacteristicProxy
|
|
30
28
|
from bumble.gatt_adapters import (
|
|
31
29
|
PackedCharacteristicAdapter,
|
|
32
30
|
PackedCharacteristicProxyAdapter,
|
|
33
31
|
)
|
|
32
|
+
from bumble.gatt_client import CharacteristicProxy, ProfileServiceProxy
|
|
34
33
|
|
|
35
34
|
|
|
36
35
|
# -----------------------------------------------------------------------------
|
bumble/profiles/cap.py
CHANGED
|
@@ -18,8 +18,7 @@
|
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
from __future__ import annotations
|
|
20
20
|
|
|
21
|
-
from bumble import gatt
|
|
22
|
-
from bumble import gatt_client
|
|
21
|
+
from bumble import gatt, gatt_client
|
|
23
22
|
from bumble.profiles import csip
|
|
24
23
|
|
|
25
24
|
|
bumble/profiles/csip.py
CHANGED
|
@@ -17,16 +17,12 @@
|
|
|
17
17
|
# Imports
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
from __future__ import annotations
|
|
20
|
+
|
|
20
21
|
import enum
|
|
21
22
|
import struct
|
|
22
23
|
from typing import Optional
|
|
23
24
|
|
|
24
|
-
from bumble import core
|
|
25
|
-
from bumble import crypto
|
|
26
|
-
from bumble import device
|
|
27
|
-
from bumble import gatt
|
|
28
|
-
from bumble import gatt_client
|
|
29
|
-
|
|
25
|
+
from bumble import core, crypto, device, gatt, gatt_client
|
|
30
26
|
|
|
31
27
|
# -----------------------------------------------------------------------------
|
|
32
28
|
# Constants
|
|
@@ -25,12 +25,12 @@ from bumble.gatt import (
|
|
|
25
25
|
GATT_HARDWARE_REVISION_STRING_CHARACTERISTIC,
|
|
26
26
|
GATT_MANUFACTURER_NAME_STRING_CHARACTERISTIC,
|
|
27
27
|
GATT_MODEL_NUMBER_STRING_CHARACTERISTIC,
|
|
28
|
+
GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC,
|
|
28
29
|
GATT_SERIAL_NUMBER_STRING_CHARACTERISTIC,
|
|
29
30
|
GATT_SOFTWARE_REVISION_STRING_CHARACTERISTIC,
|
|
30
31
|
GATT_SYSTEM_ID_CHARACTERISTIC,
|
|
31
|
-
GATT_REGULATORY_CERTIFICATION_DATA_LIST_CHARACTERISTIC,
|
|
32
|
-
TemplateService,
|
|
33
32
|
Characteristic,
|
|
33
|
+
TemplateService,
|
|
34
34
|
)
|
|
35
35
|
from bumble.gatt_adapters import (
|
|
36
36
|
DelegatedCharacteristicProxyAdapter,
|
bumble/profiles/gap.py
CHANGED
|
@@ -23,11 +23,11 @@ from typing import Optional, Union
|
|
|
23
23
|
|
|
24
24
|
from bumble.core import Appearance
|
|
25
25
|
from bumble.gatt import (
|
|
26
|
-
TemplateService,
|
|
27
|
-
Characteristic,
|
|
28
|
-
GATT_GENERIC_ACCESS_SERVICE,
|
|
29
|
-
GATT_DEVICE_NAME_CHARACTERISTIC,
|
|
30
26
|
GATT_APPEARANCE_CHARACTERISTIC,
|
|
27
|
+
GATT_DEVICE_NAME_CHARACTERISTIC,
|
|
28
|
+
GATT_GENERIC_ACCESS_SERVICE,
|
|
29
|
+
Characteristic,
|
|
30
|
+
TemplateService,
|
|
31
31
|
)
|
|
32
32
|
from bumble.gatt_adapters import (
|
|
33
33
|
DelegatedCharacteristicProxyAdapter,
|
bumble/profiles/gatt_service.py
CHANGED
|
@@ -17,10 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
import struct
|
|
18
18
|
from typing import TYPE_CHECKING
|
|
19
19
|
|
|
20
|
-
from bumble import att
|
|
21
|
-
from bumble import gatt
|
|
22
|
-
from bumble import gatt_client
|
|
23
|
-
from bumble import crypto
|
|
20
|
+
from bumble import att, crypto, gatt, gatt_client
|
|
24
21
|
|
|
25
22
|
if TYPE_CHECKING:
|
|
26
23
|
from bumble import device
|
bumble/profiles/gmap.py
CHANGED
|
@@ -18,21 +18,21 @@
|
|
|
18
18
|
# Imports
|
|
19
19
|
# -----------------------------------------------------------------------------
|
|
20
20
|
import struct
|
|
21
|
+
from enum import IntFlag
|
|
21
22
|
from typing import Optional
|
|
22
23
|
|
|
23
24
|
from bumble.gatt import (
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
GATT_BGR_FEATURES_CHARACTERISTIC,
|
|
26
|
+
GATT_BGS_FEATURES_CHARACTERISTIC,
|
|
26
27
|
GATT_GAMING_AUDIO_SERVICE,
|
|
27
28
|
GATT_GMAP_ROLE_CHARACTERISTIC,
|
|
28
29
|
GATT_UGG_FEATURES_CHARACTERISTIC,
|
|
29
30
|
GATT_UGT_FEATURES_CHARACTERISTIC,
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
Characteristic,
|
|
32
|
+
TemplateService,
|
|
32
33
|
)
|
|
33
34
|
from bumble.gatt_adapters import DelegatedCharacteristicProxyAdapter
|
|
34
35
|
from bumble.gatt_client import CharacteristicProxy, ProfileServiceProxy, ServiceProxy
|
|
35
|
-
from enum import IntFlag
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
# -----------------------------------------------------------------------------
|
bumble/profiles/hap.py
CHANGED
|
@@ -16,16 +16,15 @@
|
|
|
16
16
|
# Imports
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
from __future__ import annotations
|
|
19
|
+
|
|
19
20
|
import asyncio
|
|
20
|
-
import functools
|
|
21
|
-
from dataclasses import dataclass, field
|
|
22
21
|
import logging
|
|
22
|
+
from dataclasses import dataclass, field
|
|
23
23
|
from typing import Any, Optional, Union
|
|
24
24
|
|
|
25
|
-
from bumble import att, gatt, gatt_adapters, gatt_client
|
|
25
|
+
from bumble import att, gatt, gatt_adapters, gatt_client, utils
|
|
26
26
|
from bumble.core import InvalidArgumentError, InvalidStateError
|
|
27
|
-
from bumble.device import
|
|
28
|
-
from bumble import utils
|
|
27
|
+
from bumble.device import Connection, Device
|
|
29
28
|
from bumble.hci import Address
|
|
30
29
|
|
|
31
30
|
|
|
@@ -272,7 +271,7 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
272
271
|
def on_connection(connection: Connection) -> None:
|
|
273
272
|
@connection.on(connection.EVENT_DISCONNECTION)
|
|
274
273
|
def on_disconnection(_reason) -> None:
|
|
275
|
-
self.currently_connected_clients.
|
|
274
|
+
self.currently_connected_clients.discard(connection)
|
|
276
275
|
|
|
277
276
|
@connection.on(connection.EVENT_PAIRING)
|
|
278
277
|
def on_pairing(*_: Any) -> None:
|
|
@@ -373,8 +372,7 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
373
372
|
self.preset_records[key]
|
|
374
373
|
for key in sorted(self.preset_records.keys())
|
|
375
374
|
if self.preset_records[key].index >= start_index
|
|
376
|
-
]
|
|
377
|
-
del presets[num_presets:]
|
|
375
|
+
][:num_presets]
|
|
378
376
|
if len(presets) == 0:
|
|
379
377
|
raise att.ATT_Error(att.ErrorCode.OUT_OF_RANGE)
|
|
380
378
|
|
|
@@ -383,7 +381,10 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
383
381
|
async def _read_preset_response(
|
|
384
382
|
self, connection: Connection, presets: list[PresetRecord]
|
|
385
383
|
):
|
|
386
|
-
# If the ATT bearer is terminated before all notifications or indications are
|
|
384
|
+
# If the ATT bearer is terminated before all notifications or indications are
|
|
385
|
+
# sent, then the server shall consider the Read Presets Request operation
|
|
386
|
+
# aborted and shall not either continue or restart the operation when the client
|
|
387
|
+
# reconnects.
|
|
387
388
|
try:
|
|
388
389
|
for i, preset in enumerate(presets):
|
|
389
390
|
await connection.device.indicate_subscriber(
|
|
@@ -404,7 +405,7 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
404
405
|
|
|
405
406
|
async def generic_update(self, op: PresetChangedOperation) -> None:
|
|
406
407
|
'''Server API to perform a generic update. It is the responsibility of the caller to modify the preset_records to match the PresetChangedOperation being sent'''
|
|
407
|
-
await self.
|
|
408
|
+
await self._notify_preset_operations(op)
|
|
408
409
|
|
|
409
410
|
async def delete_preset(self, index: int) -> None:
|
|
410
411
|
'''Server API to delete a preset. It should not be the current active preset'''
|
|
@@ -413,14 +414,14 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
413
414
|
raise InvalidStateError('Cannot delete active preset')
|
|
414
415
|
|
|
415
416
|
del self.preset_records[index]
|
|
416
|
-
await self.
|
|
417
|
+
await self._notify_preset_operations(PresetChangedOperationDeleted(index))
|
|
417
418
|
|
|
418
419
|
async def available_preset(self, index: int) -> None:
|
|
419
420
|
'''Server API to make a preset available'''
|
|
420
421
|
|
|
421
422
|
preset = self.preset_records[index]
|
|
422
423
|
preset.properties.is_available = PresetRecord.Property.IsAvailable.IS_AVAILABLE
|
|
423
|
-
await self.
|
|
424
|
+
await self._notify_preset_operations(PresetChangedOperationAvailable(index))
|
|
424
425
|
|
|
425
426
|
async def unavailable_preset(self, index: int) -> None:
|
|
426
427
|
'''Server API to make a preset unavailable. It should not be the current active preset'''
|
|
@@ -432,7 +433,7 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
432
433
|
preset.properties.is_available = (
|
|
433
434
|
PresetRecord.Property.IsAvailable.IS_UNAVAILABLE
|
|
434
435
|
)
|
|
435
|
-
await self.
|
|
436
|
+
await self._notify_preset_operations(PresetChangedOperationUnavailable(index))
|
|
436
437
|
|
|
437
438
|
async def _preset_changed_operation(self, connection: Connection) -> None:
|
|
438
439
|
'''Send all PresetChangedOperation saved for a given connection'''
|
|
@@ -447,8 +448,10 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
447
448
|
return op.additional_parameters
|
|
448
449
|
|
|
449
450
|
op_list.sort(key=get_op_index)
|
|
450
|
-
# If the ATT bearer is terminated before all notifications or indications are
|
|
451
|
-
|
|
451
|
+
# If the ATT bearer is terminated before all notifications or indications are
|
|
452
|
+
# sent, then the server shall consider the Preset Changed operation aborted and
|
|
453
|
+
# shall continue the operation when the client reconnects.
|
|
454
|
+
while op_list:
|
|
452
455
|
try:
|
|
453
456
|
await connection.device.indicate_subscriber(
|
|
454
457
|
connection,
|
|
@@ -460,14 +463,15 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
460
463
|
except TimeoutError:
|
|
461
464
|
break
|
|
462
465
|
|
|
463
|
-
async def
|
|
464
|
-
for
|
|
465
|
-
|
|
466
|
+
async def _notify_preset_operations(self, op: PresetChangedOperation) -> None:
|
|
467
|
+
for history_list in self.preset_changed_operations_history_per_device.values():
|
|
468
|
+
history_list.append(op)
|
|
466
469
|
|
|
467
470
|
for connection in self.currently_connected_clients:
|
|
468
471
|
await self._preset_changed_operation(connection)
|
|
469
472
|
|
|
470
473
|
async def _on_write_preset_name(self, connection: Connection, value: bytes):
|
|
474
|
+
del connection # Unused
|
|
471
475
|
|
|
472
476
|
if self.read_presets_request_in_progress:
|
|
473
477
|
raise att.ATT_Error(att.ErrorCode.PROCEDURE_ALREADY_IN_PROGRESS)
|
|
@@ -532,48 +536,51 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
532
536
|
self.active_preset_index = index
|
|
533
537
|
await self.notify_active_preset()
|
|
534
538
|
|
|
535
|
-
async def _on_set_active_preset(self,
|
|
539
|
+
async def _on_set_active_preset(self, connection: Connection, value: bytes):
|
|
540
|
+
del connection # Unused
|
|
536
541
|
await self.set_active_preset(value)
|
|
537
542
|
|
|
538
|
-
async def set_next_or_previous_preset(self, is_previous):
|
|
543
|
+
async def set_next_or_previous_preset(self, is_previous: bool) -> None:
|
|
539
544
|
'''Set the next or the previous preset as active'''
|
|
540
545
|
|
|
541
546
|
if self.active_preset_index == 0x00:
|
|
542
547
|
raise att.ATT_Error(ErrorCode.PRESET_OPERATION_NOT_POSSIBLE)
|
|
543
548
|
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
if
|
|
549
|
+
presets = sorted(
|
|
550
|
+
[
|
|
551
|
+
record
|
|
552
|
+
for record in self.preset_records.values()
|
|
553
|
+
if record.is_available()
|
|
554
|
+
],
|
|
555
|
+
key=lambda record: record.index,
|
|
556
|
+
)
|
|
557
|
+
current_preset = self.preset_records[self.active_preset_index]
|
|
558
|
+
current_preset_pos = presets.index(current_preset)
|
|
559
|
+
if is_previous:
|
|
560
|
+
new_preset = presets[(current_preset_pos - 1) % len(presets)]
|
|
561
|
+
else:
|
|
562
|
+
new_preset = presets[(current_preset_pos + 1) % len(presets)]
|
|
563
|
+
|
|
564
|
+
if current_preset == new_preset: # If no other preset are available
|
|
560
565
|
raise att.ATT_Error(ErrorCode.PRESET_OPERATION_NOT_POSSIBLE)
|
|
561
566
|
|
|
562
|
-
|
|
563
|
-
self.active_preset_index = next_preset.index
|
|
564
|
-
else:
|
|
565
|
-
self.active_preset_index = first_preset.index
|
|
567
|
+
self.active_preset_index = new_preset.index
|
|
566
568
|
await self.notify_active_preset()
|
|
567
569
|
|
|
568
|
-
async def _on_set_next_preset(self,
|
|
570
|
+
async def _on_set_next_preset(self, connection: Connection, value: bytes) -> None:
|
|
571
|
+
del connection, value # Unused.
|
|
569
572
|
await self.set_next_or_previous_preset(False)
|
|
570
573
|
|
|
571
|
-
async def _on_set_previous_preset(
|
|
574
|
+
async def _on_set_previous_preset(
|
|
575
|
+
self, connection: Connection, value: bytes
|
|
576
|
+
) -> None:
|
|
577
|
+
del connection, value # Unused.
|
|
572
578
|
await self.set_next_or_previous_preset(True)
|
|
573
579
|
|
|
574
580
|
async def _on_set_active_preset_synchronized_locally(
|
|
575
|
-
self,
|
|
581
|
+
self, connection: Connection, value: bytes
|
|
576
582
|
):
|
|
583
|
+
del connection # Unused.
|
|
577
584
|
if (
|
|
578
585
|
self.server_features.preset_synchronization_support
|
|
579
586
|
== PresetSynchronizationSupport.PRESET_SYNCHRONIZATION_IS_NOT_SUPPORTED
|
|
@@ -584,8 +591,9 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
584
591
|
await self.other_server_in_binaural_set.set_active_preset(value)
|
|
585
592
|
|
|
586
593
|
async def _on_set_next_preset_synchronized_locally(
|
|
587
|
-
self,
|
|
594
|
+
self, connection: Connection, value: bytes
|
|
588
595
|
):
|
|
596
|
+
del connection, value # Unused.
|
|
589
597
|
if (
|
|
590
598
|
self.server_features.preset_synchronization_support
|
|
591
599
|
== PresetSynchronizationSupport.PRESET_SYNCHRONIZATION_IS_NOT_SUPPORTED
|
|
@@ -596,8 +604,9 @@ class HearingAccessService(gatt.TemplateService):
|
|
|
596
604
|
await self.other_server_in_binaural_set.set_next_or_previous_preset(False)
|
|
597
605
|
|
|
598
606
|
async def _on_set_previous_preset_synchronized_locally(
|
|
599
|
-
self,
|
|
607
|
+
self, connection: Connection, value: bytes
|
|
600
608
|
):
|
|
609
|
+
del connection, value # Unused.
|
|
601
610
|
if (
|
|
602
611
|
self.server_features.preset_synchronization_support
|
|
603
612
|
== PresetSynchronizationSupport.PRESET_SYNCHRONIZATION_IS_NOT_SUPPORTED
|
|
@@ -615,11 +624,13 @@ class HearingAccessServiceProxy(gatt_client.ProfileServiceProxy):
|
|
|
615
624
|
SERVICE_CLASS = HearingAccessService
|
|
616
625
|
|
|
617
626
|
hearing_aid_preset_control_point: gatt_client.CharacteristicProxy
|
|
618
|
-
preset_control_point_indications: asyncio.Queue
|
|
619
|
-
active_preset_index_notification: asyncio.Queue
|
|
627
|
+
preset_control_point_indications: asyncio.Queue[bytes]
|
|
628
|
+
active_preset_index_notification: asyncio.Queue[bytes]
|
|
620
629
|
|
|
621
630
|
def __init__(self, service_proxy: gatt_client.ServiceProxy) -> None:
|
|
622
631
|
self.service_proxy = service_proxy
|
|
632
|
+
self.preset_control_point_indications = asyncio.Queue()
|
|
633
|
+
self.active_preset_index_notification = asyncio.Queue()
|
|
623
634
|
|
|
624
635
|
self.server_features = gatt_adapters.PackedCharacteristicProxyAdapter(
|
|
625
636
|
service_proxy.get_characteristics_by_uuid(
|
|
@@ -641,20 +652,12 @@ class HearingAccessServiceProxy(gatt_client.ProfileServiceProxy):
|
|
|
641
652
|
'B',
|
|
642
653
|
)
|
|
643
654
|
|
|
644
|
-
async def setup_subscription(self):
|
|
645
|
-
self.preset_control_point_indications = asyncio.Queue()
|
|
646
|
-
self.active_preset_index_notification = asyncio.Queue()
|
|
647
|
-
|
|
648
|
-
def on_active_preset_index_notification(data: bytes):
|
|
649
|
-
self.active_preset_index_notification.put_nowait(data)
|
|
650
|
-
|
|
651
|
-
def on_preset_control_point_indication(data: bytes):
|
|
652
|
-
self.preset_control_point_indications.put_nowait(data)
|
|
653
|
-
|
|
655
|
+
async def setup_subscription(self) -> None:
|
|
654
656
|
await self.hearing_aid_preset_control_point.subscribe(
|
|
655
|
-
|
|
657
|
+
self.preset_control_point_indications.put_nowait,
|
|
658
|
+
prefer_notify=False,
|
|
656
659
|
)
|
|
657
660
|
|
|
658
661
|
await self.active_preset_index.subscribe(
|
|
659
|
-
|
|
662
|
+
self.active_preset_index_notification.put_nowait
|
|
660
663
|
)
|
|
@@ -17,20 +17,21 @@
|
|
|
17
17
|
# Imports
|
|
18
18
|
# -----------------------------------------------------------------------------
|
|
19
19
|
from __future__ import annotations
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
import struct
|
|
22
|
+
from enum import IntEnum
|
|
22
23
|
from typing import Optional
|
|
23
24
|
|
|
24
25
|
from bumble import core
|
|
25
26
|
from bumble.att import ATT_Error
|
|
26
27
|
from bumble.gatt import (
|
|
27
|
-
GATT_HEART_RATE_SERVICE,
|
|
28
|
-
GATT_HEART_RATE_MEASUREMENT_CHARACTERISTIC,
|
|
29
28
|
GATT_BODY_SENSOR_LOCATION_CHARACTERISTIC,
|
|
30
29
|
GATT_HEART_RATE_CONTROL_POINT_CHARACTERISTIC,
|
|
31
|
-
|
|
30
|
+
GATT_HEART_RATE_MEASUREMENT_CHARACTERISTIC,
|
|
31
|
+
GATT_HEART_RATE_SERVICE,
|
|
32
32
|
Characteristic,
|
|
33
33
|
CharacteristicValue,
|
|
34
|
+
TemplateService,
|
|
34
35
|
)
|
|
35
36
|
from bumble.gatt_adapters import (
|
|
36
37
|
DelegatedCharacteristicAdapter,
|
bumble/profiles/le_audio.py
CHANGED
|
@@ -16,14 +16,16 @@
|
|
|
16
16
|
# Imports
|
|
17
17
|
# -----------------------------------------------------------------------------
|
|
18
18
|
from __future__ import annotations
|
|
19
|
+
|
|
19
20
|
import dataclasses
|
|
20
21
|
import enum
|
|
21
22
|
import struct
|
|
22
23
|
from typing import Any
|
|
24
|
+
|
|
23
25
|
from typing_extensions import Self
|
|
24
26
|
|
|
25
|
-
from bumble.profiles import bap
|
|
26
27
|
from bumble import utils
|
|
28
|
+
from bumble.profiles import bap
|
|
27
29
|
|
|
28
30
|
|
|
29
31
|
# -----------------------------------------------------------------------------
|