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/rtp.py ADDED
@@ -0,0 +1,110 @@
1
+ # Copyright 2024 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # https://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ # -----------------------------------------------------------------------------
16
+ # Imports
17
+ # -----------------------------------------------------------------------------
18
+ from __future__ import annotations
19
+ import struct
20
+ from typing import List
21
+
22
+
23
+ # -----------------------------------------------------------------------------
24
+ class MediaPacket:
25
+ @staticmethod
26
+ def from_bytes(data: bytes) -> MediaPacket:
27
+ version = (data[0] >> 6) & 0x03
28
+ padding = (data[0] >> 5) & 0x01
29
+ extension = (data[0] >> 4) & 0x01
30
+ csrc_count = data[0] & 0x0F
31
+ marker = (data[1] >> 7) & 0x01
32
+ payload_type = data[1] & 0x7F
33
+ sequence_number = struct.unpack_from('>H', data, 2)[0]
34
+ timestamp = struct.unpack_from('>I', data, 4)[0]
35
+ ssrc = struct.unpack_from('>I', data, 8)[0]
36
+ csrc_list = [
37
+ struct.unpack_from('>I', data, 12 + i)[0] for i in range(csrc_count)
38
+ ]
39
+ payload = data[12 + csrc_count * 4 :]
40
+
41
+ return MediaPacket(
42
+ version,
43
+ padding,
44
+ extension,
45
+ marker,
46
+ sequence_number,
47
+ timestamp,
48
+ ssrc,
49
+ csrc_list,
50
+ payload_type,
51
+ payload,
52
+ )
53
+
54
+ def __init__(
55
+ self,
56
+ version: int,
57
+ padding: int,
58
+ extension: int,
59
+ marker: int,
60
+ sequence_number: int,
61
+ timestamp: int,
62
+ ssrc: int,
63
+ csrc_list: List[int],
64
+ payload_type: int,
65
+ payload: bytes,
66
+ ) -> None:
67
+ self.version = version
68
+ self.padding = padding
69
+ self.extension = extension
70
+ self.marker = marker
71
+ self.sequence_number = sequence_number & 0xFFFF
72
+ self.timestamp = timestamp & 0xFFFFFFFF
73
+ self.timestamp_seconds = 0.0
74
+ self.ssrc = ssrc
75
+ self.csrc_list = csrc_list
76
+ self.payload_type = payload_type
77
+ self.payload = payload
78
+
79
+ def __bytes__(self) -> bytes:
80
+ header = bytes(
81
+ [
82
+ self.version << 6
83
+ | self.padding << 5
84
+ | self.extension << 4
85
+ | len(self.csrc_list),
86
+ self.marker << 7 | self.payload_type,
87
+ ]
88
+ ) + struct.pack(
89
+ '>HII',
90
+ self.sequence_number,
91
+ self.timestamp,
92
+ self.ssrc,
93
+ )
94
+ for csrc in self.csrc_list:
95
+ header += struct.pack('>I', csrc)
96
+ return header + self.payload
97
+
98
+ def __str__(self) -> str:
99
+ return (
100
+ f'RTP(v={self.version},'
101
+ f'p={self.padding},'
102
+ f'x={self.extension},'
103
+ f'm={self.marker},'
104
+ f'pt={self.payload_type},'
105
+ f'sn={self.sequence_number},'
106
+ f'ts={self.timestamp},'
107
+ f'ssrc={self.ssrc},'
108
+ f'csrcs={self.csrc_list},'
109
+ f'payload_size={len(self.payload)})'
110
+ )
bumble/smp.py CHANGED
@@ -764,7 +764,9 @@ class Session:
764
764
  self.peer_io_capability = SMP_NO_INPUT_NO_OUTPUT_IO_CAPABILITY
765
765
 
766
766
  # OOB
767
- self.oob_data_flag = 0 if pairing_config.oob is None else 1
767
+ self.oob_data_flag = (
768
+ 1 if pairing_config.oob and pairing_config.oob.peer_data else 0
769
+ )
768
770
 
769
771
  # Set up addresses
770
772
  self_address = connection.self_resolvable_address or connection.self_address
@@ -1014,8 +1016,10 @@ class Session:
1014
1016
  self.send_command(response)
1015
1017
 
1016
1018
  def send_pairing_confirm_command(self) -> None:
1017
- self.r = crypto.r()
1018
- logger.debug(f'generated random: {self.r.hex()}')
1019
+
1020
+ if self.pairing_method != PairingMethod.OOB:
1021
+ self.r = crypto.r()
1022
+ logger.debug(f'generated random: {self.r.hex()}')
1019
1023
 
1020
1024
  if self.sc:
1021
1025
 
@@ -1735,7 +1739,6 @@ class Session:
1735
1739
  if self.pairing_method in (
1736
1740
  PairingMethod.JUST_WORKS,
1737
1741
  PairingMethod.NUMERIC_COMPARISON,
1738
- PairingMethod.OOB,
1739
1742
  ):
1740
1743
  ra = bytes(16)
1741
1744
  rb = ra
@@ -1743,6 +1746,22 @@ class Session:
1743
1746
  assert self.passkey
1744
1747
  ra = self.passkey.to_bytes(16, byteorder='little')
1745
1748
  rb = ra
1749
+ elif self.pairing_method == PairingMethod.OOB:
1750
+ if self.is_initiator:
1751
+ if self.peer_oob_data:
1752
+ rb = self.peer_oob_data.r
1753
+ ra = self.r
1754
+ else:
1755
+ rb = bytes(16)
1756
+ ra = self.r
1757
+ else:
1758
+ if self.peer_oob_data:
1759
+ ra = self.peer_oob_data.r
1760
+ rb = self.r
1761
+ else:
1762
+ ra = bytes(16)
1763
+ rb = self.r
1764
+
1746
1765
  else:
1747
1766
  return
1748
1767
 
@@ -70,6 +70,9 @@ def get_ini_dir() -> Optional[pathlib.Path]:
70
70
  elif sys.platform == 'linux':
71
71
  if xdg_runtime_dir := os.environ.get('XDG_RUNTIME_DIR', None):
72
72
  return pathlib.Path(xdg_runtime_dir)
73
+ tmpdir = os.environ.get('TMPDIR', '/tmp')
74
+ if pathlib.Path(tmpdir).is_dir():
75
+ return pathlib.Path(tmpdir)
73
76
  elif sys.platform == 'win32':
74
77
  if local_app_data_dir := os.environ.get('LOCALAPPDATA', None):
75
78
  return pathlib.Path(local_app_data_dir) / 'Temp'
bumble/transport/pyusb.py CHANGED
@@ -23,7 +23,7 @@ import time
23
23
  import usb.core
24
24
  import usb.util
25
25
 
26
- from typing import Optional
26
+ from typing import Optional, Set
27
27
  from usb.core import Device as UsbDevice
28
28
  from usb.core import USBError
29
29
  from usb.util import CTRL_TYPE_CLASS, CTRL_RECIPIENT_OTHER
@@ -46,6 +46,11 @@ RESET_DELAY = 3
46
46
  # -----------------------------------------------------------------------------
47
47
  logger = logging.getLogger(__name__)
48
48
 
49
+ # -----------------------------------------------------------------------------
50
+ # Global
51
+ # -----------------------------------------------------------------------------
52
+ devices_in_use: Set[int] = set()
53
+
49
54
 
50
55
  # -----------------------------------------------------------------------------
51
56
  async def open_pyusb_transport(spec: str) -> Transport:
@@ -217,6 +222,8 @@ async def open_pyusb_transport(spec: str) -> Transport:
217
222
  await self.source.stop()
218
223
  await self.sink.stop()
219
224
  usb.util.release_interface(self.device, 0)
225
+ if devices_in_use and device.address in devices_in_use:
226
+ devices_in_use.remove(device.address)
220
227
 
221
228
  usb_find = usb.core.find
222
229
  try:
@@ -233,7 +240,18 @@ async def open_pyusb_transport(spec: str) -> Transport:
233
240
  spec = spec[1:]
234
241
  if ':' in spec:
235
242
  vendor_id, product_id = spec.split(':')
236
- device = usb_find(idVendor=int(vendor_id, 16), idProduct=int(product_id, 16))
243
+ device = None
244
+ devices = usb_find(
245
+ find_all=True, idVendor=int(vendor_id, 16), idProduct=int(product_id, 16)
246
+ )
247
+ for d in devices:
248
+ if d.address in devices_in_use:
249
+ continue
250
+ device = d
251
+ devices_in_use.add(d.address)
252
+ break
253
+ if device is None:
254
+ raise ValueError('device already in use')
237
255
  elif '-' in spec:
238
256
 
239
257
  def device_path(device):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bumble
3
- Version: 0.0.198
3
+ Version: 0.0.200
4
4
  Summary: Bluetooth Stack for Apps, Emulation, Test and Experimentation
5
5
  Home-page: https://github.com/google/bumble
6
6
  Author: Google
@@ -27,7 +27,7 @@ Requires-Dist: pyusb>=1.2; platform_system != "Emscripten"
27
27
  Requires-Dist: websockets>=12.0; platform_system != "Emscripten"
28
28
  Requires-Dist: cryptography>=39.0; platform_system == "Emscripten"
29
29
  Provides-Extra: avatar
30
- Requires-Dist: pandora-avatar==0.0.9; extra == "avatar"
30
+ Requires-Dist: pandora-avatar==0.0.10; extra == "avatar"
31
31
  Requires-Dist: rootcanal==1.10.0; python_version >= "3.10" and extra == "avatar"
32
32
  Provides-Extra: build
33
33
  Requires-Dist: build>=0.7; extra == "build"
@@ -1,38 +1,39 @@
1
1
  bumble/__init__.py,sha256=Q8jkz6rgl95IMAeInQVt_2GLoJl3DcEP2cxtrQ-ho5c,110
2
- bumble/_version.py,sha256=wj4Uoyl4fbIliDzkMZfA-f07UNZEG-IYvFEisYUdjJ0,415
3
- bumble/a2dp.py,sha256=VEeAOCfT1ZqpwnEgel6DJ32vxR8jYX3IAaBfCqPdWO8,22675
2
+ bumble/_version.py,sha256=QkvzoUjUmzIu-0WPLCIoPkyy_n8BoMLliGVrvjz6i7A,415
3
+ bumble/a2dp.py,sha256=_dCq-qyG5OglDVlaOFwAgFe_ugvHuEdEYL-kWFf6sWQ,31775
4
4
  bumble/at.py,sha256=Giu2VUSJKH-jIh10lOfumiqy-FyO99Ra6nJ7UiWQ0H8,3114
5
- bumble/att.py,sha256=TGzhhBKCQPA_P_eDDSNASJVfa3dCr-QzzrRB3GekrI0,32366
6
- bumble/avc.py,sha256=Ho-WweU9lU15vlTwIbrGBa18M5vUKYm5q8aToaLSh70,16311
5
+ bumble/att.py,sha256=S-ha1Xn2YHf8k_c6JCXDv1QwiGJAJvgpHVLVxo1kkPQ,32755
6
+ bumble/avc.py,sha256=OZz5_DYenPeg2PcNM3dpgV5PUs4D7FBSNOcSqsuRJ2w,16329
7
7
  bumble/avctp.py,sha256=yHAjJRjLGtR0Q-iWcLS7cJRz5Jr2YiRmZd6LZV4Xjt4,9935
8
- bumble/avdtp.py,sha256=6kx4FiFHuV6zmYYrHYnJO4ilDksJauyu9d6XBO4wPVg,77450
9
- bumble/avrcp.py,sha256=BhDjc8TxhOpPnuvGn5-dGB6JK1aqshg4x7tm_vI4LLU,69363
8
+ bumble/avdtp.py,sha256=2ki_BE4SHiu3Sx9oHCknfjF-bBcgPB9TsyF5upciUYI,76773
9
+ bumble/avrcp.py,sha256=P_pLVpP3kRtoD2y0Ca0NTEEe1mA4SXO_ldtc4OP6Tcc,69976
10
10
  bumble/bridge.py,sha256=T6es5oS1dy8QgkxQ8iOD-YcZ0SWOv8jaqC7TGxqodk4,3003
11
- bumble/codecs.py,sha256=yels_alICohfM5DuvR2wMpYlebt7OrZHCtRXWyMyYYI,15581
11
+ bumble/codecs.py,sha256=75TGfq-XWWtr-mCRRG7QzJYNRebG50Ypt_QGQkoWlxU,20915
12
12
  bumble/colors.py,sha256=CC5tBDnN86bvlbYf1KIVdyj7QBLaqEDT_hQVB0p7FeU,3118
13
13
  bumble/company_ids.py,sha256=B68e2QPsDeRYP9jjbGs4GGDwEkGxcXGTsON_CHA0uuI,118528
14
14
  bumble/controller.py,sha256=XkYTQb2J5MhH_dGfnFkrLXdChFD2s1wSvqXaHQFeo48,59688
15
15
  bumble/core.py,sha256=T43ZszjsU_89B0UJwQ9GCzvKU7oj1_RBzsdGr9jX9xY,72440
16
16
  bumble/crypto.py,sha256=L6z3dn9-dgKYRtOM6O3F6n6Ju4PwTM3LAFJtCg_ie78,9382
17
- bumble/decoder.py,sha256=N9nMvuVhuwpnfw7EDVuNe9uYY6B6c3RY2dh8RhRPC1U,9608
18
- bumble/device.py,sha256=4TcC6v_zwyTcZMAMZd7qb06oLVGtw84LtdlgIsilFbU,194632
17
+ bumble/decoder.py,sha256=0-VNWZT-u7lvK3qBpAuYT0M6Rz_bMgMi4CjfUXX_6RM,9728
18
+ bumble/device.py,sha256=vroAnNWlBW6_jw1KgmoG4ZWKyauLm8abS1XFrTX084Y,195024
19
19
  bumble/gap.py,sha256=dRU2_TWvqTDx80hxeSbXlWIeWvptWH4_XbItG5y948Q,2138
20
- bumble/gatt.py,sha256=FiueS6Uj4go3LB7PjhXlzLHBFiiiMJWiuHtsILEuVLo,38651
21
- bumble/gatt_client.py,sha256=C8HlxEYpe3FBOPS2RXZZ9_tX3KfqPnn0XZsmhakSXNc,43332
22
- bumble/gatt_server.py,sha256=uPYbn2-y0MLnyR8xxpOf18gPua_Q49pSlMR1zxEnU-Q,37118
23
- bumble/hci.py,sha256=v4JeftZq-j1XYCNUwgBH_3JnXOpJ_cJCYmj1HO6GKzE,275223
20
+ bumble/gatt.py,sha256=a07mQ3O0LFt5zgUzSUwa4Jak_FXOXSFX-njxnQNS_zY,39014
21
+ bumble/gatt_client.py,sha256=gIpgNQj5WNm9RirXXT4vuXQZ4WK82IFMOqnfqBtoYRU,42809
22
+ bumble/gatt_server.py,sha256=pafGMeAuGAAELnr_1pB_l3CcR5u4H4Y1-MRHjN53gdE,37449
23
+ bumble/hci.py,sha256=e2JqP-D1h7b7vHxFbmdsLJtOacdiuMizzGgBWmCAhxQ,286058
24
24
  bumble/helpers.py,sha256=m0w4UgFFNDEnXwHrDyfRlcBObdVed2fqXGL0lvR3c8s,12733
25
- bumble/hfp.py,sha256=OsBDREelxhLMi_UZO9Kxlqzbts08CcGxoiicUgrYlXg,75353
25
+ bumble/hfp.py,sha256=h5IcgxKnlFWapeJHcNDTvxup9oAE5CcZju92sOusTGc,75619
26
26
  bumble/hid.py,sha256=hJKm6qhNa0kQTGmp_VxNh3-ywgBDdJpPPFcvtFiRL0A,20335
27
- bumble/host.py,sha256=OIV1_Alfjn6-VbvnHzmnFuuXt6kVZ0zvIptaj3waRe4,48415
27
+ bumble/host.py,sha256=pPH7HTQ6ogOToj4Y5Jl985MKjbVlG_jeOcJrV0NTSqU,49204
28
28
  bumble/keys.py,sha256=WbIQ7Ob81mW75qmEPQ2rBLfnqBMA-ts2yowWXP9UaCY,12654
29
29
  bumble/l2cap.py,sha256=Bu6oTD3DzqLOKiarynT1cfQefNgR0gCJoKxnwQJl2_o,81398
30
30
  bumble/link.py,sha256=MYKsIKpbbAkh_ldxPZKu_GhS90ImC0IQtCAqbY4Ddg4,24034
31
31
  bumble/pairing.py,sha256=tgPUba6xNxMi-2plm3xfRlzHq-uPRNZEIGWaN0qNGCs,9853
32
32
  bumble/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
33
33
  bumble/rfcomm.py,sha256=dh5t5vlDEfw3yHgQfzegMYPnShP8Zo-3ScABUvmXNLI,40751
34
+ bumble/rtp.py,sha256=388X3aCv-QrWJ37r_VPqXYJtvNGWPsHnJasqs41g_-s,3487
34
35
  bumble/sdp.py,sha256=aajRQybcMWh_Kc4IuQahix6bXnHg61OXl1gSdrSysl4,45465
35
- bumble/smp.py,sha256=h8KSaBMSPeVSU_wwRPUnRu2wFSXW-J_ez8FQSOayH4s,77040
36
+ bumble/smp.py,sha256=FNLn-pt2n6CKNttQGJJDnfaeof2SVkxlapwySHWAVJY,77640
36
37
  bumble/snoop.py,sha256=1mzwmp9LToUXbPnFsLrt8S4UHs0kqzbu7LDydwbmkZI,5715
37
38
  bumble/utils.py,sha256=e0i-4d28-9zP3gYcd1rdNd669rkPnRs5oJCERUEDfxo,15099
38
39
  bumble/apps/README.md,sha256=XTwjRAY-EJWDXpl1V8K3Mw8B7kIqzUIUizRjVBVhoIE,1769
@@ -41,7 +42,7 @@ bumble/apps/auracast.py,sha256=hrG6dW79UkMXqcMLgYjziWEjcVibFUITvjPb4LX1lxM,24686
41
42
  bumble/apps/bench.py,sha256=nPACg5gQWxJ-6phze12FVCv1_WS2UjrWR7OUWj0o8PU,56350
42
43
  bumble/apps/ble_rpa_tool.py,sha256=ZQtsbfnLPd5qUAkEBPpNgJLRynBBc7q_9cDHKUW2SQ0,1701
43
44
  bumble/apps/console.py,sha256=rwD9y3g8Mm_mAEvrcXjbtcv5d8mwF3yTbmE6Vet2BEk,45300
44
- bumble/apps/controller_info.py,sha256=m29omI2r8q01GccgN6Lb-HfSsBjYdGpLDHlgZ99ldTM,9249
45
+ bumble/apps/controller_info.py,sha256=WScuK5Ytp5aFEosAcgRTCEeey6SmxDFmyB7KBhgVx6s,11759
45
46
  bumble/apps/controller_loopback.py,sha256=VJAFsUdFwm2KgOrRuLADymMpZl5qVO0RGkDSr-1XKtY,7214
46
47
  bumble/apps/controllers.py,sha256=R6XJ1XpyuXlyqSCmI7PromVIcoYTcYfpmO-TqTYXnUI,2326
47
48
  bumble/apps/device_info.py,sha256=kQSO7F60cmUKw99LHfyly9s_ox2mD0dNGsgxCnKoFOQ,7999
@@ -49,7 +50,7 @@ bumble/apps/gatt_dump.py,sha256=wwA-NhRnbgUkbj-Ukym7NDG2j2n_36t_tn93dLDVdIg,4487
49
50
  bumble/apps/gg_bridge.py,sha256=JdW5QT6xN9c2XDDJoHDRo5W3N_RdVkCtTmlcOsJhlx8,14693
50
51
  bumble/apps/hci_bridge.py,sha256=KISv352tKnsQsoxjkDiCQbMFmhnPWdnug5wSFAAXxEs,4033
51
52
  bumble/apps/l2cap_bridge.py,sha256=524VgEmgCP4g7T0UdgmsePmNVhDFRJECeaZ_uzKsbco,13062
52
- bumble/apps/pair.py,sha256=COU2D7YAIn4lo5iuM0ClObA1zZqQCdrXOcnsiCm0YlQ,17529
53
+ bumble/apps/pair.py,sha256=NtDxLfdnlOY_ZEtVNGVXWjv6_x_hndok_ydhV6zkFtI,18503
53
54
  bumble/apps/pandora_server.py,sha256=5qaoLCpcZE2KsGO21-7t6Vg4dBjBWbnyOQXwrLhxkuE,1397
54
55
  bumble/apps/rfcomm_bridge.py,sha256=PSszh4Qh1IsIw8ETs0fevOCAXEdVtqlgnV-ruzqGrZI,17215
55
56
  bumble/apps/scan.py,sha256=b6hIppiJqDfR7VFW2wl3-lkPdFvHLqYZKY8VjjNnhls,8366
@@ -62,26 +63,29 @@ bumble/apps/lea_unicast/liblc3.wasm,sha256=nYMzG9fP8_71K9dQfVI9QPQPkFRPHoqZEEExs
62
63
  bumble/apps/link_relay/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
63
64
  bumble/apps/link_relay/link_relay.py,sha256=GOESYPzkMJFrz5VOI_BSmnmgz4Y8EdSLHMWgdA63aDg,10066
64
65
  bumble/apps/link_relay/logging.yml,sha256=t-P72RAHsTZOESw0M4I3CQPonymcjkd9SLE0eY_ZNiM,311
66
+ bumble/apps/player/player.py,sha256=hht867HimxaO-ZgPxZB3OYLNJv6eaR55BUgBlCSGR6U,22370
65
67
  bumble/apps/speaker/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
66
68
  bumble/apps/speaker/logo.svg,sha256=SQ9XXIqhh07BnGaBZ653nJ7vOslm2Dogdqadhg2MdE4,4205
67
69
  bumble/apps/speaker/speaker.css,sha256=nyM5TjzDYkkLwFzsaIOuTSngzSvgDnkLe0Z-fAn1_t4,1234
68
70
  bumble/apps/speaker/speaker.html,sha256=kfAZ5oZSFc9ygBFIUuZEn5LUNQnHBvrnuHU6VAptyiU,1188
69
71
  bumble/apps/speaker/speaker.js,sha256=DrT831yg3oBXKZ5usnfZjRU9X6Nw3zjIWSkz6sIgVtw,9373
70
- bumble/apps/speaker/speaker.py,sha256=f7cOyVqD6HOiLPCgdcnwN7sakj2SScybVHVTBR6eFwk,24197
72
+ bumble/apps/speaker/speaker.py,sha256=OTqygA9VbQW_XxTxqxS0vRW_wvhnKHssSxDz1lQZ9ZU,24763
71
73
  bumble/drivers/__init__.py,sha256=lxqJTghh21rQFThRTurwLysZm385TUcn8ZdpHQSWD88,3196
72
74
  bumble/drivers/common.py,sha256=pS783hudolLZAzF8IUWp7g6TXyQsUCEzqCsd1VGeYfQ,1507
73
75
  bumble/drivers/intel.py,sha256=-YcJI4ZC_fhHHxWyE8b4eB8V7suOFH1n9uayckGE9Uw,3231
74
- bumble/drivers/rtk.py,sha256=xFPzTxSJYVTIkru2D3oQMtAcNCAXSChhMSIsE7ksO8I,21552
75
- bumble/pandora/__init__.py,sha256=5NBVmndeTulANawift0jPT9ISp562wyIHTZ-4uP34Mg,3283
76
+ bumble/drivers/rtk.py,sha256=nsfAqNzvxvAwbh6UYgxOCSNwgw7XouIBFA03FrLTs4M,22088
77
+ bumble/pandora/__init__.py,sha256=jaPtYCLfLeLUGj8-TmS3Gkv0l1_DBadYj8ZMAPLPAao,3463
76
78
  bumble/pandora/config.py,sha256=KD85n3oRbuvD65sRah2H0gpxEW4YbD7HbYbsxdcpDDA,2388
77
79
  bumble/pandora/device.py,sha256=LFqCWrgYkQWrFUSKArsAABXkge8sB2DhvaQoEsC4Jn0,5344
78
80
  bumble/pandora/host.py,sha256=LnEQ3DJAhmJVgHA7VyokvypQejsi2VcbauSFYn1a9Jk,39235
81
+ bumble/pandora/l2cap.py,sha256=OT-pPprVAQr7xwjYnNwDQujayG2zWUS5FPXVBGNCW3o,11725
79
82
  bumble/pandora/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
83
  bumble/pandora/security.py,sha256=YErueKNLsnmcRe6dKo724Ht-buOqmZl2Gauswcc8FW0,21946
81
84
  bumble/pandora/utils.py,sha256=Fq4glL0T5cJ2FODoDotmDNdYFOkTOR7DyyL8vkcxp20,3949
82
85
  bumble/profiles/__init__.py,sha256=yBGC8Ti5LvZuoh1F42XtfrBilb39T77_yuxESZeX2yI,581
86
+ bumble/profiles/aics.py,sha256=U0K03XqOKtqahXtq7U47WxftsAD7tkiDeUqxfaF4pwk,18540
83
87
  bumble/profiles/ascs.py,sha256=Y2_fd_5LOb9hon60LcQl3R-FoAIsOd_J37RZpveh-7c,25471
84
- bumble/profiles/asha_service.py,sha256=J4i5jkJciZWMtTWJ1zGJkEx65DlAEIADqjCRYf_CWNs,7220
88
+ bumble/profiles/asha.py,sha256=QXUp7ImuMD48L0mpuNxPcIkv8VvoENynCuF2PEVqzFM,10373
85
89
  bumble/profiles/bap.py,sha256=wLnrbXso203rgw0WNa91qIdMdjuIoGc9VqOHc9Ey_b4,19421
86
90
  bumble/profiles/bass.py,sha256=Wiqum0Wsr5PpVzTAPDcyKLTfJoKXJUYOzqB320aSiUs,14950
87
91
  bumble/profiles/battery_service.py,sha256=w-uF4jLoDozJOoykimb2RkrKjVyCke6ts2-h-F1PYyc,2292
@@ -89,6 +93,7 @@ bumble/profiles/cap.py,sha256=6gH7oOnUKjOggMPuB7rtbwj0AneoNmnWzQ_iR3io8e0,1945
89
93
  bumble/profiles/csip.py,sha256=qpI9W0_FWIpsuJrHhxfbKaa-TD21epxEa3EuCm8gh6c,10156
90
94
  bumble/profiles/device_information_service.py,sha256=RfqnXywcwcSTiFalxd1LVTTdeWLxHGsMvlvr9fI0GJI,6193
91
95
  bumble/profiles/gap.py,sha256=jUjfy6MPL7k6wgNn3ny3PVgSX6-SLmjUepFYHjGc3IU,3870
96
+ bumble/profiles/hap.py,sha256=IbE1KzjIMEq6FxtFqTgA2DN0pPnpu0996KJRjuN3oaQ,25614
92
97
  bumble/profiles/heart_rate_service.py,sha256=_MG1ApmF1B7b4xRzELuahtRWzLm49i9O4m7I6ZFU4mw,8644
93
98
  bumble/profiles/le_audio.py,sha256=1x6OpIc0JMa32YVcfM8lq6jnXHlriHUcOkAs0EttJJk,3093
94
99
  bumble/profiles/mcp.py,sha256=vIN1r_if4LmOcGCgZuDYTYLMQzU6-1pKUFx1Z3iSAeY,17415
@@ -96,20 +101,20 @@ bumble/profiles/pacs.py,sha256=bhlU5M6E9e1YKf-qJnJL3GwTqOPuSvYDpY_UYq0Nnd8,8730
96
101
  bumble/profiles/pbp.py,sha256=51aoQcZMXzTzeatHd0zNVN7kYcv4atzr2OWpzxlSVP8,1630
97
102
  bumble/profiles/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
98
103
  bumble/profiles/tmap.py,sha256=hpz5VYEdEOty4D9ApCRDero9Tf3L9arSZWnLCNkZoHI,3005
99
- bumble/profiles/vcp.py,sha256=wkbTf2NRCbBtvpXplpNJq4dzXp6JGeaEHeeC1kHqW7s,7897
104
+ bumble/profiles/vcp.py,sha256=Lx1Odg7PQO9nXkpxRpK04MRuy975uIK8kSqcwrk4iSE,8035
100
105
  bumble/tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
106
  bumble/tools/generate_company_id_list.py,sha256=ysbPb3zmxKFBiSQ_MBG2r15-sqR5P_GWT6i0YUTTXOM,1736
102
107
  bumble/tools/rtk_fw_download.py,sha256=KEPG-rDrdPGKBzZ78P4s3udLRYT3p7vesGhXvJTWTic,5453
103
108
  bumble/tools/rtk_util.py,sha256=TwZhupHQrQYsYHLdRGyzXKd24pwCk8kkzqK1Rj2guco,5087
104
109
  bumble/transport/__init__.py,sha256=Z01fvuKpqAbhJd0wYcGhW09W2tycM71ck80XoZ8a87Q,7012
105
110
  bumble/transport/android_emulator.py,sha256=6HR2cEqdU0XbOldwxCtQuXtvwOUYhRfHkPz0TRt3mbo,4382
106
- bumble/transport/android_netsim.py,sha256=39RYKZJX806nbS6I2Yu31Z9h7-FJgYGIshXUoT0GjS8,16315
111
+ bumble/transport/android_netsim.py,sha256=bQ1XSNloAsqanyEQMmcTpZX6csiZNdowoYDh-JskDZY,16447
107
112
  bumble/transport/common.py,sha256=bJWYH-vRJJl0nWwlAjGTHrRQFdZayKkH7YoGor5abH8,16659
108
113
  bumble/transport/file.py,sha256=eVM2V6Nk2nDAFdE7Rt01ZI3JdTovsH9OEU1gKYPJjpE,2010
109
114
  bumble/transport/hci_socket.py,sha256=EdgWi3-O5yvYcH4R4BkPtG79pnUo7GQtXWawuUHDoDQ,6331
110
115
  bumble/transport/pty.py,sha256=grTl-yvjMWHflNwuME4ccVqDbk6NIEgQMgH6Y9lf1fU,2732
111
116
  bumble/transport/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
112
- bumble/transport/pyusb.py,sha256=znHdx0h_XNiDVa7bs2qlq9sG4vURlK8XloApZ73InDo,15532
117
+ bumble/transport/pyusb.py,sha256=7l0y3qo3_LYv1wyKtGC5d0Si2t49F574NIA4XZu70jk,16181
113
118
  bumble/transport/serial.py,sha256=loQxkeG7uE09enXWg2uGbxi6CeG70wn3kzPbEwULKw4,2446
114
119
  bumble/transport/tcp_client.py,sha256=deyUJYpj04QE00Mw_PTU5PHPA6mr1Nui3f5-QCy2zOw,1854
115
120
  bumble/transport/tcp_server.py,sha256=tvu7FuPeqiXfoj2HQU8wu4AiwKjDDDCKlKjgtqWc5hg,3779
@@ -152,9 +157,9 @@ bumble/vendor/android/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3h
152
157
  bumble/vendor/android/hci.py,sha256=GZrkhaWmcMt1JpnRhv0NoySGkf2H4lNUV2f_omRZW0I,10741
153
158
  bumble/vendor/zephyr/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
159
  bumble/vendor/zephyr/hci.py,sha256=d83bC0TvT947eN4roFjLkQefWtHOoNsr4xib2ctSkvA,3195
155
- bumble-0.0.198.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
156
- bumble-0.0.198.dist-info/METADATA,sha256=fVbh2d9h95IUX4z5lP0FC4aXJ2WGsWX8Wb8gMKyjfLw,5672
157
- bumble-0.0.198.dist-info/WHEEL,sha256=Mdi9PDNwEZptOjTlUcAth7XJDFtKrHYaQMPulZeBCiQ,91
158
- bumble-0.0.198.dist-info/entry_points.txt,sha256=AOFf_gnWbZ7jk5fzspxXHCQUay1ik71pK3HYO7sZQsk,937
159
- bumble-0.0.198.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
160
- bumble-0.0.198.dist-info/RECORD,,
160
+ bumble-0.0.200.dist-info/LICENSE,sha256=FvaYh4NRWIGgS_OwoBs5gFgkCmAghZ-DYnIGBZPuw-s,12142
161
+ bumble-0.0.200.dist-info/METADATA,sha256=JusrKVEENpezz89ImgV1FiIA5pBG9OoZK6Ic2ass0ac,5673
162
+ bumble-0.0.200.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
163
+ bumble-0.0.200.dist-info/entry_points.txt,sha256=2TAnDAHiYVEo9Gnugk29QIsHpCgRgnPqBszLSgIX2T0,984
164
+ bumble-0.0.200.dist-info/top_level.txt,sha256=tV6JJKaHPYMFiJYiBYFW24PCcfLxTJZdlu6BmH3Cb00,7
165
+ bumble-0.0.200.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (73.0.1)
2
+ Generator: setuptools (75.2.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -10,6 +10,7 @@ bumble-l2cap-bridge = bumble.apps.l2cap_bridge:main
10
10
  bumble-link-relay = bumble.apps.link_relay.link_relay:main
11
11
  bumble-pair = bumble.apps.pair:main
12
12
  bumble-pandora-server = bumble.apps.pandora_server:main
13
+ bumble-player = bumble.apps.player.player:main
13
14
  bumble-rfcomm-bridge = bumble.apps.rfcomm_bridge:main
14
15
  bumble-rtk-fw-download = bumble.tools.rtk_fw_download:main
15
16
  bumble-rtk-util = bumble.tools.rtk_util:main
@@ -1,193 +0,0 @@
1
- # Copyright 2021-2022 Google LLC
2
- #
3
- # Licensed under the Apache License, Version 2.0 (the "License");
4
- # you may not use this file except in compliance with the License.
5
- # You may obtain a copy of the License at
6
- #
7
- # https://www.apache.org/licenses/LICENSE-2.0
8
- #
9
- # Unless required by applicable law or agreed to in writing, software
10
- # distributed under the License is distributed on an "AS IS" BASIS,
11
- # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- # See the License for the specific language governing permissions and
13
- # limitations under the License.
14
-
15
-
16
- # -----------------------------------------------------------------------------
17
- # Imports
18
- # -----------------------------------------------------------------------------
19
- import struct
20
- import logging
21
- from typing import List, Optional
22
-
23
- from bumble import l2cap
24
- from ..core import AdvertisingData
25
- from ..device import Device, Connection
26
- from ..gatt import (
27
- GATT_ASHA_SERVICE,
28
- GATT_ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC,
29
- GATT_ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC,
30
- GATT_ASHA_AUDIO_STATUS_CHARACTERISTIC,
31
- GATT_ASHA_VOLUME_CHARACTERISTIC,
32
- GATT_ASHA_LE_PSM_OUT_CHARACTERISTIC,
33
- TemplateService,
34
- Characteristic,
35
- CharacteristicValue,
36
- )
37
- from ..utils import AsyncRunner
38
-
39
- # -----------------------------------------------------------------------------
40
- # Logging
41
- # -----------------------------------------------------------------------------
42
- logger = logging.getLogger(__name__)
43
-
44
-
45
- # -----------------------------------------------------------------------------
46
- class AshaService(TemplateService):
47
- UUID = GATT_ASHA_SERVICE
48
- OPCODE_START = 1
49
- OPCODE_STOP = 2
50
- OPCODE_STATUS = 3
51
- PROTOCOL_VERSION = 0x01
52
- RESERVED_FOR_FUTURE_USE = [00, 00]
53
- FEATURE_MAP = [0x01] # [LE CoC audio output streaming supported]
54
- SUPPORTED_CODEC_ID = [0x02, 0x01] # Codec IDs [G.722 at 16 kHz]
55
- RENDER_DELAY = [00, 00]
56
-
57
- def __init__(self, capability: int, hisyncid: List[int], device: Device, psm=0):
58
- self.hisyncid = hisyncid
59
- self.capability = capability # Device Capabilities [Left, Monaural]
60
- self.device = device
61
- self.audio_out_data = b''
62
- self.psm = psm # a non-zero psm is mainly for testing purpose
63
-
64
- # Handler for volume control
65
- def on_volume_write(connection, value):
66
- logger.info(f'--- VOLUME Write:{value[0]}')
67
- self.emit('volume', connection, value[0])
68
-
69
- # Handler for audio control commands
70
- def on_audio_control_point_write(connection: Optional[Connection], value):
71
- logger.info(f'--- AUDIO CONTROL POINT Write:{value.hex()}')
72
- opcode = value[0]
73
- if opcode == AshaService.OPCODE_START:
74
- # Start
75
- audio_type = ('Unknown', 'Ringtone', 'Phone Call', 'Media')[value[2]]
76
- logger.info(
77
- f'### START: codec={value[1]}, '
78
- f'audio_type={audio_type}, '
79
- f'volume={value[3]}, '
80
- f'otherstate={value[4]}'
81
- )
82
- self.emit(
83
- 'start',
84
- connection,
85
- {
86
- 'codec': value[1],
87
- 'audiotype': value[2],
88
- 'volume': value[3],
89
- 'otherstate': value[4],
90
- },
91
- )
92
- elif opcode == AshaService.OPCODE_STOP:
93
- logger.info('### STOP')
94
- self.emit('stop', connection)
95
- elif opcode == AshaService.OPCODE_STATUS:
96
- logger.info(f'### STATUS: connected={value[1]}')
97
-
98
- # OPCODE_STATUS does not need audio status point update
99
- if opcode != AshaService.OPCODE_STATUS:
100
- AsyncRunner.spawn(
101
- device.notify_subscribers(
102
- self.audio_status_characteristic, force=True
103
- )
104
- )
105
-
106
- self.read_only_properties_characteristic = Characteristic(
107
- GATT_ASHA_READ_ONLY_PROPERTIES_CHARACTERISTIC,
108
- Characteristic.Properties.READ,
109
- Characteristic.READABLE,
110
- bytes(
111
- [
112
- AshaService.PROTOCOL_VERSION, # Version
113
- self.capability,
114
- ]
115
- )
116
- + bytes(self.hisyncid)
117
- + bytes(AshaService.FEATURE_MAP)
118
- + bytes(AshaService.RENDER_DELAY)
119
- + bytes(AshaService.RESERVED_FOR_FUTURE_USE)
120
- + bytes(AshaService.SUPPORTED_CODEC_ID),
121
- )
122
-
123
- self.audio_control_point_characteristic = Characteristic(
124
- GATT_ASHA_AUDIO_CONTROL_POINT_CHARACTERISTIC,
125
- Characteristic.Properties.WRITE
126
- | Characteristic.Properties.WRITE_WITHOUT_RESPONSE,
127
- Characteristic.WRITEABLE,
128
- CharacteristicValue(write=on_audio_control_point_write),
129
- )
130
- self.audio_status_characteristic = Characteristic(
131
- GATT_ASHA_AUDIO_STATUS_CHARACTERISTIC,
132
- Characteristic.Properties.READ | Characteristic.Properties.NOTIFY,
133
- Characteristic.READABLE,
134
- bytes([0]),
135
- )
136
- self.volume_characteristic = Characteristic(
137
- GATT_ASHA_VOLUME_CHARACTERISTIC,
138
- Characteristic.Properties.WRITE_WITHOUT_RESPONSE,
139
- Characteristic.WRITEABLE,
140
- CharacteristicValue(write=on_volume_write),
141
- )
142
-
143
- # Register an L2CAP CoC server
144
- def on_coc(channel):
145
- def on_data(data):
146
- logging.debug(f'<<< data received:{data}')
147
-
148
- self.emit('data', channel.connection, data)
149
- self.audio_out_data += data
150
-
151
- channel.sink = on_data
152
-
153
- # let the server find a free PSM
154
- self.psm = device.create_l2cap_server(
155
- spec=l2cap.LeCreditBasedChannelSpec(psm=self.psm, max_credits=8),
156
- handler=on_coc,
157
- ).psm
158
- self.le_psm_out_characteristic = Characteristic(
159
- GATT_ASHA_LE_PSM_OUT_CHARACTERISTIC,
160
- Characteristic.Properties.READ,
161
- Characteristic.READABLE,
162
- struct.pack('<H', self.psm),
163
- )
164
-
165
- characteristics = [
166
- self.read_only_properties_characteristic,
167
- self.audio_control_point_characteristic,
168
- self.audio_status_characteristic,
169
- self.volume_characteristic,
170
- self.le_psm_out_characteristic,
171
- ]
172
-
173
- super().__init__(characteristics)
174
-
175
- def get_advertising_data(self):
176
- # Advertisement only uses 4 least significant bytes of the HiSyncId.
177
- return bytes(
178
- AdvertisingData(
179
- [
180
- (
181
- AdvertisingData.SERVICE_DATA_16_BIT_UUID,
182
- bytes(GATT_ASHA_SERVICE)
183
- + bytes(
184
- [
185
- AshaService.PROTOCOL_VERSION,
186
- self.capability,
187
- ]
188
- )
189
- + bytes(self.hisyncid[:4]),
190
- ),
191
- ]
192
- )
193
- )