diff --git a/bumble/profiles/bap.py b/bumble/profiles/bap.py index a1cae1b..ef94d54 100644 --- a/bumble/profiles/bap.py +++ b/bumble/profiles/bap.py @@ -553,6 +553,80 @@ class CodecSpecificCapabilities: ) +@dataclasses.dataclass +class CodecSpecificConfiguration: + '''See: + * Bluetooth Assigned Numbers, 6.12.5 - Codec Specific Configuration LTV Structures + * Basic Audio Profile, 4.3.2 - Codec_Specific_Capabilities LTV requirements + ''' + + class Type(enum.IntEnum): + # fmt: off + SAMPLING_FREQUENCY = 0x01 + FRAME_DURATION = 0x02 + AUDIO_CHANNEL_ALLOCATION = 0x03 + OCTETS_PER_FRAME = 0x04 + CODEC_FRAMES_PER_SDU = 0x05 + + sampling_frequency: SamplingFrequency + frame_duration: FrameDuration + audio_channel_allocation: AudioLocation + octets_per_codec_frame: int + codec_frames_per_sdu: int + + @classmethod + def from_bytes(cls, data: bytes) -> CodecSpecificConfiguration: + offset = 0 + # Allowed default values. + audio_channel_allocation = AudioLocation.NOT_ALLOWED + codec_frames_per_sdu = 1 + while offset < len(data): + length, type = struct.unpack_from('BB', data, offset) + offset += 2 + value = int.from_bytes(data[offset : offset + length - 1], 'little') + offset += length - 1 + + if type == CodecSpecificConfiguration.Type.SAMPLING_FREQUENCY: + sampling_frequency = SamplingFrequency(value) + elif type == CodecSpecificConfiguration.Type.FRAME_DURATION: + frame_duration = FrameDuration(value) + elif type == CodecSpecificConfiguration.Type.AUDIO_CHANNEL_ALLOCATION: + audio_channel_allocation = AudioLocation(value) + elif type == CodecSpecificConfiguration.Type.OCTETS_PER_FRAME: + octets_per_codec_frame = value + elif type == CodecSpecificConfiguration.Type.CODEC_FRAMES_PER_SDU: + codec_frames_per_sdu = value + + # It is expected here that if some fields are missing, an error should be raised. + return CodecSpecificConfiguration( + sampling_frequency=sampling_frequency, + frame_duration=frame_duration, + audio_channel_allocation=audio_channel_allocation, + octets_per_codec_frame=octets_per_codec_frame, + codec_frames_per_sdu=codec_frames_per_sdu, + ) + + def __bytes__(self) -> bytes: + return struct.pack( + '