Coverage for src / bluetooth_sig / gatt / characteristics / source_pac.py: 100%

20 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-03 16:41 +0000

1"""Source PAC characteristic (0x2BCB).""" 

2 

3from __future__ import annotations 

4 

5import msgspec 

6 

7from ..context import CharacteristicContext 

8from .base import BaseCharacteristic 

9from .utils import DataParser 

10 

11 

12class SourcePACData(msgspec.Struct, frozen=True, kw_only=True): # pylint: disable=too-few-public-methods 

13 """Parsed data from Source PAC characteristic. 

14 

15 Contains the number of PAC records and the raw record data. 

16 Full PAC record parsing is complex (codec_id + capabilities + metadata) 

17 and stored as raw bytes for downstream consumers. 

18 """ 

19 

20 number_of_pac_records: int 

21 raw_data: bytes 

22 

23 

24class SourcePACCharacteristic(BaseCharacteristic[SourcePACData]): 

25 """Source PAC characteristic (0x2BCB). 

26 

27 org.bluetooth.characteristic.source_pac 

28 

29 Published Audio Capabilities for the source role. 

30 Contains codec capabilities for audio transmission. 

31 """ 

32 

33 min_length = 1 

34 allow_variable_length = True 

35 

36 def _decode_value( 

37 self, data: bytearray, ctx: CharacteristicContext | None = None, *, validate: bool = True 

38 ) -> SourcePACData: 

39 """Parse Source PAC data. 

40 

41 Format: number_of_pac_records (uint8) + variable PAC records. 

42 """ 

43 record_count = DataParser.parse_int8(data, 0, signed=False) 

44 raw_data = bytes(data[1:]) if len(data) > 1 else b"" 

45 return SourcePACData( 

46 number_of_pac_records=record_count, 

47 raw_data=raw_data, 

48 ) 

49 

50 def _encode_value(self, data: SourcePACData) -> bytearray: 

51 """Encode Source PAC data to bytes.""" 

52 result = bytearray() 

53 result += DataParser.encode_int8(data.number_of_pac_records) 

54 result += bytearray(data.raw_data) 

55 return result