bumble 0.0.218__py3-none-any.whl → 0.0.219__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 CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '0.0.218'
32
- __version_tuple__ = version_tuple = (0, 0, 218)
31
+ __version__ = version = '0.0.219'
32
+ __version_tuple__ = version_tuple = (0, 0, 219)
33
33
 
34
34
  __commit_id__ = commit_id = None
bumble/a2dp.py CHANGED
@@ -21,11 +21,12 @@ import dataclasses
21
21
  import enum
22
22
  import logging
23
23
  import struct
24
- from collections.abc import AsyncGenerator
25
- from typing import Awaitable, Callable
24
+ from collections.abc import AsyncGenerator, Awaitable, Callable
25
+ from typing import Union
26
26
 
27
27
  from typing_extensions import ClassVar, Self
28
28
 
29
+ from bumble import utils
29
30
  from bumble.codecs import AacAudioRtpPacket
30
31
  from bumble.company_ids import COMPANY_IDENTIFIERS
31
32
  from bumble.core import (
@@ -59,19 +60,18 @@ logger = logging.getLogger(__name__)
59
60
  # -----------------------------------------------------------------------------
60
61
  # fmt: off
61
62
 
62
- A2DP_SBC_CODEC_TYPE = 0x00
63
- A2DP_MPEG_1_2_AUDIO_CODEC_TYPE = 0x01
64
- A2DP_MPEG_2_4_AAC_CODEC_TYPE = 0x02
65
- A2DP_ATRAC_FAMILY_CODEC_TYPE = 0x03
66
- A2DP_NON_A2DP_CODEC_TYPE = 0xFF
67
-
68
- A2DP_CODEC_TYPE_NAMES = {
69
- A2DP_SBC_CODEC_TYPE: 'A2DP_SBC_CODEC_TYPE',
70
- A2DP_MPEG_1_2_AUDIO_CODEC_TYPE: 'A2DP_MPEG_1_2_AUDIO_CODEC_TYPE',
71
- A2DP_MPEG_2_4_AAC_CODEC_TYPE: 'A2DP_MPEG_2_4_AAC_CODEC_TYPE',
72
- A2DP_ATRAC_FAMILY_CODEC_TYPE: 'A2DP_ATRAC_FAMILY_CODEC_TYPE',
73
- A2DP_NON_A2DP_CODEC_TYPE: 'A2DP_NON_A2DP_CODEC_TYPE'
74
- }
63
+ class CodecType(utils.OpenIntEnum):
64
+ SBC = 0x00
65
+ MPEG_1_2_AUDIO = 0x01
66
+ MPEG_2_4_AAC = 0x02
67
+ ATRAC_FAMILY = 0x03
68
+ NON_A2DP = 0xFF
69
+
70
+ A2DP_SBC_CODEC_TYPE = CodecType.SBC
71
+ A2DP_MPEG_1_2_AUDIO_CODEC_TYPE = CodecType.MPEG_1_2_AUDIO
72
+ A2DP_MPEG_2_4_AAC_CODEC_TYPE = CodecType.MPEG_2_4_AAC
73
+ A2DP_ATRAC_FAMILY_CODEC_TYPE = CodecType.ATRAC_FAMILY
74
+ A2DP_NON_A2DP_CODEC_TYPE = CodecType.NON_A2DP
75
75
 
76
76
 
77
77
  SBC_SYNC_WORD = 0x9C
@@ -259,9 +259,48 @@ def make_audio_sink_service_sdp_records(service_record_handle, version=(1, 3)):
259
259
  ]
260
260
 
261
261
 
262
+ # -----------------------------------------------------------------------------
263
+ class MediaCodecInformation:
264
+ '''Base Media Codec Information.'''
265
+
266
+ @classmethod
267
+ def create(
268
+ cls, media_codec_type: int, data: bytes
269
+ ) -> Union[MediaCodecInformation, bytes]:
270
+ if media_codec_type == CodecType.SBC:
271
+ return SbcMediaCodecInformation.from_bytes(data)
272
+ elif media_codec_type == CodecType.MPEG_2_4_AAC:
273
+ return AacMediaCodecInformation.from_bytes(data)
274
+ elif media_codec_type == CodecType.NON_A2DP:
275
+ vendor_media_codec_information = (
276
+ VendorSpecificMediaCodecInformation.from_bytes(data)
277
+ )
278
+ if (
279
+ vendor_class_map := A2DP_VENDOR_MEDIA_CODEC_INFORMATION_CLASSES.get(
280
+ vendor_media_codec_information.vendor_id
281
+ )
282
+ ) and (
283
+ media_codec_information_class := vendor_class_map.get(
284
+ vendor_media_codec_information.codec_id
285
+ )
286
+ ):
287
+ return media_codec_information_class.from_bytes(
288
+ vendor_media_codec_information.value
289
+ )
290
+ return vendor_media_codec_information
291
+
292
+ @classmethod
293
+ def from_bytes(cls, data: bytes) -> Self:
294
+ del data # Unused.
295
+ raise NotImplementedError
296
+
297
+ def __bytes__(self) -> bytes:
298
+ raise NotImplementedError
299
+
300
+
262
301
  # -----------------------------------------------------------------------------
263
302
  @dataclasses.dataclass
264
- class SbcMediaCodecInformation:
303
+ class SbcMediaCodecInformation(MediaCodecInformation):
265
304
  '''
266
305
  A2DP spec - 4.3.2 Codec Specific Information Elements
267
306
  '''
@@ -345,7 +384,7 @@ class SbcMediaCodecInformation:
345
384
 
346
385
  # -----------------------------------------------------------------------------
347
386
  @dataclasses.dataclass
348
- class AacMediaCodecInformation:
387
+ class AacMediaCodecInformation(MediaCodecInformation):
349
388
  '''
350
389
  A2DP spec - 4.5.2 Codec Specific Information Elements
351
390
  '''
@@ -427,7 +466,7 @@ class AacMediaCodecInformation:
427
466
 
428
467
  @dataclasses.dataclass
429
468
  # -----------------------------------------------------------------------------
430
- class VendorSpecificMediaCodecInformation:
469
+ class VendorSpecificMediaCodecInformation(MediaCodecInformation):
431
470
  '''
432
471
  A2DP spec - 4.7.2 Codec Specific Information Elements
433
472
  '''
bumble/avctp.py CHANGED
@@ -19,10 +19,11 @@ from __future__ import annotations
19
19
 
20
20
  import logging
21
21
  import struct
22
+ from collections.abc import Callable
22
23
  from enum import IntEnum
23
- from typing import Callable, Optional, cast
24
+ from typing import Optional
24
25
 
25
- from bumble import avc, core, l2cap
26
+ from bumble import core, l2cap
26
27
  from bumble.colors import color
27
28
 
28
29
  # -----------------------------------------------------------------------------
@@ -144,9 +145,9 @@ class MessageAssembler:
144
145
 
145
146
  # -----------------------------------------------------------------------------
146
147
  class Protocol:
147
- CommandHandler = Callable[[int, avc.CommandFrame], None]
148
+ CommandHandler = Callable[[int, bytes], None]
148
149
  command_handlers: dict[int, CommandHandler] # Command handlers, by PID
149
- ResponseHandler = Callable[[int, Optional[avc.ResponseFrame]], None]
150
+ ResponseHandler = Callable[[int, Optional[bytes]], None]
150
151
  response_handlers: dict[int, ResponseHandler] # Response handlers, by PID
151
152
  next_transaction_label: int
152
153
  message_assembler: MessageAssembler
@@ -204,20 +205,15 @@ class Protocol:
204
205
  self.send_ipid(transaction_label, pid)
205
206
  return
206
207
 
207
- command_frame = cast(avc.CommandFrame, avc.Frame.from_bytes(payload))
208
- self.command_handlers[pid](transaction_label, command_frame)
208
+ self.command_handlers[pid](transaction_label, payload)
209
209
  else:
210
210
  if pid not in self.response_handlers:
211
211
  logger.warning(f"no response handler for PID {pid}")
212
212
  return
213
213
 
214
214
  # By convention, for an ipid, send a None payload to the response handler.
215
- if ipid:
216
- response_frame = None
217
- else:
218
- response_frame = cast(avc.ResponseFrame, avc.Frame.from_bytes(payload))
219
-
220
- self.response_handlers[pid](transaction_label, response_frame)
215
+ response_payload = None if ipid else payload
216
+ self.response_handlers[pid](transaction_label, response_payload)
221
217
 
222
218
  def send_message(
223
219
  self,