From 4a21eef6011794a99bd48cabeda8356a15b0eb64 Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Mon, 22 Feb 2021 08:47:17 +0700 Subject: [PATCH 1/2] implement useable subset of USB Audio Class 2.0 --- usb_protocol/emitters/descriptors/uac2.py | 39 ++ usb_protocol/types/descriptors/uac.py | 421 ++++++++++++++++++++++ usb_protocol/types/descriptors/uac2.py | 306 ++++++++++++++++ usb_protocol/types/descriptors/uac3.py | 167 +++++++++ 4 files changed, 933 insertions(+) create mode 100644 usb_protocol/emitters/descriptors/uac2.py create mode 100644 usb_protocol/types/descriptors/uac.py create mode 100644 usb_protocol/types/descriptors/uac2.py create mode 100644 usb_protocol/types/descriptors/uac3.py diff --git a/usb_protocol/emitters/descriptors/uac2.py b/usb_protocol/emitters/descriptors/uac2.py new file mode 100644 index 0000000..d15bd4e --- /dev/null +++ b/usb_protocol/emitters/descriptors/uac2.py @@ -0,0 +1,39 @@ +# +# This file is part of usb_protocol. +# +""" Convenience emitters for USB Audio Class 2 descriptors. """ + +from contextlib import contextmanager + +from .. import emitter_for_format +from ...types.descriptors.uac import * +from ...types.descriptors.uac2 import * +from ...emitters.descriptor import ComplexDescriptorEmitter + +# Create our emitters. +InterfaceAssociationDescriptorEmitter = emitter_for_format(InterfaceAssociationDescriptor) +StandardAudioControlInterfaceDescriptorEmitter = emitter_for_format(StandardAudioControlInterfaceDescriptor) + +class ClassSpecificAudioControlInterfaceDescriptorEmitter(ComplexDescriptorEmitter): + DESCRIPTOR_FORMAT = ClassSpecificAudioControlInterfaceDescriptor + + def _pre_emit(self): + # Figure out the total length of our descriptor, including subordinates. + subordinate_length = sum(len(sub) for sub in self._subordinates) + self.wTotalLength = subordinate_length + self.DESCRIPTOR_FORMAT.sizeof() + +ClockSourceDescriptorEmitter = emitter_for_format(ClockSourceDescriptor) +InputTerminalDescriptorEmitter = emitter_for_format(InputTerminalDescriptor) +OutputTerminalDescriptorEmitter = emitter_for_format(OutputTerminalDescriptor) +AudioStreamingInterfaceDescriptorEmitter = emitter_for_format(AudioStreamingInterfaceDescriptor) +ClassSpecificAudioStreamingInterfaceDescriptorEmitter = emitter_for_format(ClassSpecificAudioStreamingInterfaceDescriptor) +TypeIFormatTypeDescriptorEmitter = emitter_for_format(TypeIFormatTypeDescriptor) +ExtendedTypeIFormatTypeDescriptorEmitter = emitter_for_format(ExtendedTypeIFormatTypeDescriptor) +TypeIIFormatTypeDescriptorEmitter = emitter_for_format(TypeIIFormatTypeDescriptor) +ExtendedTypeIIFormatTypeDescriptorEmitter = emitter_for_format(ExtendedTypeIIFormatTypeDescriptor) +TypeIIIFormatTypeDescriptorEmitter = emitter_for_format(TypeIIIFormatTypeDescriptor) +ExtendedTypeIIIFormatTypeDescriptorEmitter = emitter_for_format(ExtendedTypeIIIFormatTypeDescriptor) +ClassSpecificAudioStreamingIsochronousAudioDataEndpointDescriptorEmitter = emitter_for_format(ClassSpecificAudioStreamingIsochronousAudioDataEndpointDescriptor) +AudioControlInterruptEndpointDescriptorEmitter = emitter_for_format(AudioControlInterruptEndpointDescriptor) +AudioStreamingIsochronousEndpointDescriptorEmitter = emitter_for_format(AudioStreamingIsochronousEndpointDescriptor) +AudioStreamingIsochronousFeedbackEndpointDescriptorEmitter = emitter_for_format(AudioStreamingIsochronousFeedbackEndpointDescriptor) diff --git a/usb_protocol/types/descriptors/uac.py b/usb_protocol/types/descriptors/uac.py new file mode 100644 index 0000000..796dec3 --- /dev/null +++ b/usb_protocol/types/descriptors/uac.py @@ -0,0 +1,421 @@ +# +# This file is part of usb-protocol. +# +""" common USB audio enums and descriptors """ + +from build.lib.usb_protocol.emitters import descriptor +import unittest +from enum import IntEnum + +import construct +from construct import this, Default + +from .. import LanguageIDs +from ..descriptor import \ + DescriptorField, DescriptorNumber, DescriptorFormat, \ + BCDFieldAdapter, DescriptorLength + +class AudioInterfaceClassCode(IntEnum): + AUDIO = 0x01 + +class AudioFunctionClassCode(IntEnum): + AUDIO_FUNCTION = AudioInterfaceClassCode.AUDIO + +class AudioInterfaceProtocolCodes(IntEnum): + IP_VERSION_01_00 = 0x00 + IP_VERSION_02_00 = 0x20 + IP_VERSION_03_00 = 0x30 + +class AudioFunctionProtocolCodes(IntEnum): + FUNCTION_PROTOCOL_UNDEFINED = 0x00 + AF_VERSION_01_00 = AudioInterfaceProtocolCodes.IP_VERSION_01_00 + AF_VERSION_02_00 = AudioInterfaceProtocolCodes.IP_VERSION_02_00 + AF_VERSION_03_00 = AudioInterfaceProtocolCodes.IP_VERSION_03_00 + +class AudioFunctionSubclassCodes(IntEnum): + FUNCTION_SUBCLASS_UNDEFINED = 0x00 + FULL_ADC_3_0 = 0x01 + GENERIC_IO = 0x20 + HEADPHONE = 0x21 + SPEAKER = 0x22 + MICROPHONE = 0x23 + HEADSET = 0x24 + HEADSET_ADAPTER = 0x25 + SPEAKERPHONE = 0x26 + +class AudioInterfaceSubclassCodes(IntEnum): + INTERFACE_SUBCLASS_UNDEFINED = 0x00 + AUDIO_CONTROL = 0x01 + AUDIO_STREAMING = 0x02 + MIDI_STREAMING = 0x03 + +class AudioFunctionCategoryCodes(IntEnum): + FUNCTION_SUBCLASS_UNDEFINED = 0x00 + DESKTOP_SPEAKER = 0x01 + HOME_THEATER = 0x02 + MICROPHONE = 0x03 + HEADSET = 0x04 + TELEPHONE = 0x05 + CONVERTER = 0x06 + VOICE_SOUND_RECORDER = 0x07 + IO_BOX = 0x08 + MUSICAL_INSTRUMENT = 0x09 + PRO_AUDIO = 0x0A + AUDIO_VIDEO = 0x0B + CONTROL_PANEL = 0x0C + HEADPHONE = 0x0D + GENERIC_SPEAKER = 0x0E + HEADSET_ADAPTER = 0x0F + SPEAKERPHONE = 0x10 + OTHER = 0xFF + + +class DescriptorTypes(IntEnum): + INTERFACE = 0x04 + ENDPOINT = 0x05 + INTERFACE_ASSOCIATION = 0x0B + +class AudioClassSpecificDescriptorTypes(IntEnum): + CS_UNDEFINED = 0x20 + CS_DEVICE = 0x21 + CS_CONFIGURATION = 0x22 + CS_STRING = 0x23 + CS_INTERFACE = 0x24 + CS_ENDPOINT = 0x25 + CS_CLUSTER = 0x26 + +class ClusterDescriptorSubtypes(IntEnum): + SUBTYPE_UNDEFINED = 0x00 + +class ClusterDescriptorSegmentTypes(IntEnum): + SEGMENT_UNDEFINED = 0x00 + CLUSTER_DESCRIPTION = 0x01 + CLUSTER_VENDOR_DEFINED = 0x1F + CHANNEL_INFORMATION = 0x20 + CHANNEL_AMBISONIC = 0x21 + CHANNEL_DESCRIPTION = 0x22 + CHANNEL_VENDOR_DEFINED = 0xFE + END_SEGMENT = 0xFF + +class ChannelPurposeDefinitions(IntEnum): + PURPOSE_UNDEFINED = 0x00 + GENERIC_AUDIO = 0x01 + VOICE = 0x02 + SPEECH = 0x03 + AMBIENT = 0x04 + REFERENCE = 0x05 + ULTRASONIC = 0x06 + VIBROKINETIC = 0x07 + NON_AUDIO = 0xFF + +class AmbisonicComponentOrderingConventionTypes(IntEnum): + ORD_TYPE_UNDEFINED = 0x00 + AMBISONIC_CHANNEL_NUMBER_ACN = 0x01 + FURSE_MALHAM = 0x02 + SINGLE_INDEX_DESIGNATION_SID = 0x03 + +class AmbisonicNormalizatioTypes(IntEnum): + NORM_TYPE_UNDEFINED = 0x00 + MAX_N = 0x01 + SN3D = 0x02 + N3D = 0x03 + SN2D = 0x04 + N2D = 0x05 + +class AudioClassSpecificACInterfaceDescriptorSubtypes(IntEnum): + AC_DESCRIPTOR_UNDEFINED = 0x00 + HEADER = 0x01 + INPUT_TERMINAL = 0x02 + OUTPUT_TERMINAL = 0x03 + EXTENDED_TERMINAL = 0x04 + MIXER_UNIT = 0x05 + SELECTOR_UNIT = 0x06 + FEATURE_UNIT = 0x07 + EFFECT_UNIT = 0x08 + PROCESSING_UNIT = 0x09 + EXTENSION_UNIT = 0x0A + CLOCK_SOURCE = 0x0B + CLOCK_SELECTOR = 0x0C + CLOCK_MULTIPLIER = 0x0D + SAMPLE_RATE_CONVERTER = 0x0E + CONNECTORS = 0x0F + POWER_DOMAIN = 0x10 + +class AudioClassSpecificStringDescriptorSubtypes(IntEnum): + SUBTYPE_UNDEFINED = 0x00 + +class ExtendedTerminalSegmentTypes(IntEnum): + SEGMENT_UNDEFINED = 0x00 + TERMINAL_VENDOR_DEFINED = 0x1F + CHANNEL_BANDWIDTH = 0x20 + CHANNEL_MAGNITUDE_RESPONSE = 0x21 + CHANNEL_MAGNITUDE_PHASE_RESPONSE = 0x22 + CHANNEL_POSITION_XYZ = 0x23 + CHANNEL_POSITION_R_THETA_PHI = 0x24 + CHANNEL_VENDOR_DEFINED = 0xFE + END_SEGMENT = 0xFF + +class EffectUnitEffectTypes(IntEnum): + EFFECT_UNDEFINED = 0x0000 + PARAM_EQ_SECTION_EFFECT = 0x0001 + REVERBERATION_EFFECT = 0x0002 + MOD_DELAY_EFFECT = 0x0003 + DYN_RANGE_COMP_EFFECT = 0x0004 + +class ProcessingUnitProcessTypes(IntEnum): + PROCESS_UNDEFINED = 0x0000 + UP_DOWNMIX_PROCESS = 0x0001 + STEREO_EXTENDER_PROCESS = 0x0002 + MULTI_FUNCTION_PROCESS = 0x0003 + +class AudioClassSpecificEndpointDescriptorSubtypes(IntEnum): + DESCRIPTOR_UNDEFINED = 0x00 + EP_GENERAL = 0x01 + +class AudioClassSpecificRequestCodes(IntEnum): + REQUEST_CODE_UNDEFINED = 0x00 + CUR = 0x01 + RANGE = 0x02 + MEM = 0x03 + INTEN = 0x04 + STRING = 0x05 + HIGH_CAPABILITY_DESCRIPTOR = 0x06 + +class AudioControlInterfaceControlSelectors(IntEnum): + AC_CONTROL_UNDEFINED = 0x00 + AC_ACTIVE_INTERFACE_CONTROL = 0x01 + AC_POWER_DOMAIN_CONTROL = 0x02 + +class ClockSourceControlSelectors(IntEnum): + CS_CONTROL_UNDEFINED = 0x00 + CS_SAM_FREQ_CONTROL = 0x01 + CS_CLOCK_VALID_CONTROL = 0x02 + +class ClockSelectorControlSelectors(IntEnum): + CX_CONTROL_UNDEFINED = 0x00 + CX_CLOCK_SELECTOR_CONTROL = 0x01 + +class ClockMultiplierControlSelectors(IntEnum): + CM_CONTROL_UNDEFINED = 0x00 + CM_NUMERATOR_CONTROL = 0x01 + CM_DENOMINATOR_CONTROL = 0x02 + +class TerminalControlSelectors(IntEnum): + TE_CONTROL_UNDEFINED = 0x00 + TE_INSERTION_CONTROL = 0x01 + TE_OVERLOAD_CONTROL = 0x02 + TE_UNDERFLOW_CONTROL = 0x03 + TE_OVERFLOW_CONTROL = 0x04 + TE_LATENCY_CONTROL = 0x05 + +class MixerControlSelectors(IntEnum): + MU_CONTROL_UNDEFINED = 0x00 + MU_MIXER_CONTROL = 0x01 + MU_UNDERFLOW_CONTROL = 0x02 + MU_OVERFLOW_CONTROL = 0x03 + MU_LATENCY_CONTROL = 0x04 + +class SelectorControlSelectors(IntEnum): + SU_CONTROL_UNDEFINED = 0x00 + SU_SELECTOR_CONTROL = 0x01 + SU_LATENCY_CONTROL = 0x02 + +class FeatureUnitControlSelectors(IntEnum): + FU_CONTROL_UNDEFINED = 0x00 + FU_MUTE_CONTROL = 0x01 + FU_VOLUME_CONTROL = 0x02 + FU_BASS_CONTROL = 0x03 + FU_MID_CONTROL = 0x04 + FU_TREBLE_CONTROL = 0x05 + FU_GRAPHIC_EQUALIZER_CONTROL = 0x06 + FU_AUTOMATIC_GAIN_CONTROL = 0x07 + FU_DELAY_CONTROL = 0x08 + FU_BASS_BOOST_CONTROL = 0x09 + FU_LOUDNESS_CONTROL = 0x0A + FU_INPUT_GAIN_CONTROL = 0x0B + FU_INPUT_GAIN_PAD_CONTROL = 0x0C + FU_PHASE_INVERTER_CONTROL = 0x0D + FU_UNDERFLOW_CONTROL = 0x0E + FU_OVERFLOW_CONTROL = 0x0F + FU_LATENCY_CONTROL = 0x10 + +class ParametricEqualizerSectionEffectUnitControlSelectors(IntEnum): + PE_CONTROL_UNDEFINED = 0x00 + PE_ENABLE_CONTROL = 0x01 + PE_CENTERFREQ_CONTROL = 0x02 + PE_QFACTOR_CONTROL = 0x03 + PE_GAIN_CONTROL = 0x04 + PE_UNDERFLOW_CONTROL = 0x05 + PE_OVERFLOW_CONTROL = 0x06 + PE_LATENCY_CONTROL = 0x07 + +class ReverberationEffectUnitControlSelectors(IntEnum): + RV_CONTROL_UNDEFINED = 0x00 + RV_ENABLE_CONTROL = 0x01 + RV_TYPE_CONTROL = 0x02 + RV_LEVEL_CONTROL = 0x03 + RV_TIME_CONTROL = 0x04 + RV_FEEDBACK_CONTROL = 0x05 + RV_PREDELAY_CONTROL = 0x06 + RV_DENSITY_CONTROL = 0x07 + RV_HIFREQ_ROLLOFF_CONTROL = 0x08 + RV_UNDERFLOW_CONTROL = 0x09 + RV_OVERFLOW_CONTROL = 0x0A + RV_LATENCY_CONTROL = 0x0B + +class ModulationDelayEffectUnitControlSelectors(IntEnum): + MD_CONTROL_UNDEFINED = 0x00 + MD_ENABLE_CONTROL = 0x01 + MD_BALANCE_CONTROL = 0x02 + MD_RATE_CONTROL = 0x03 + MD_DEPTH_CONTROL = 0x04 + MD_TIME_CONTROL = 0x05 + MD_FEEDBACK_CONTROL = 0x06 + MD_UNDERFLOW_CONTROL = 0x07 + MD_OVERFLOW_CONTROL = 0x08 + MD_LATENCY_CONTROL = 0x09 + +class DynamicRangeCompressorEffectUnitControlSelectors(IntEnum): + DR_CONTROL_UNDEFINED = 0x00 + DR_ENABLE_CONTROL = 0x01 + DR_COMPRESSION_RATE_CONTROL = 0x02 + DR_MAXAMPL_CONTROL = 0x03 + DR_THRESHOLD_CONTROL = 0x04 + DR_ATTACK_TIME_CONTROL = 0x05 + DR_RELEASE_TIME_CONTROL = 0x06 + DR_UNDERFLOW_CONTROL = 0x07 + DR_OVERFLOW_CONTROL = 0x08 + DR_LATENCY_CONTROL = 0x09 + +class UpDownMixProcessingUnitControlSelectors(IntEnum): + UD_CONTROL_UNDEFINED = 0x00 + UD_MODE_SELECT_CONTROL = 0x01 + UD_UNDERFLOW_CONTROL = 0x02 + UD_OVERFLOW_CONTROL = 0x03 + UD_LATENCY_CONTROL = 0x04 + +class StereoExtenderProcessingUnitControlSelectors(IntEnum): + ST_EXT_CONTROL_UNDEFINED = 0x00 + ST_EXT_WIDTH_CONTROL = 0x01 + ST_EXT_UNDERFLOW_CONTROL = 0x02 + ST_EXT_OVERFLOW_CONTROL = 0x03 + ST_EXT_LATENCY_CONTROL = 0x04 + +class ExtensionUnitControlSelectors(IntEnum): + XU_CONTROL_UNDEFINED = 0x00 + XU_UNDERFLOW_CONTROL = 0x01 + XU_OVERFLOW_CONTROL = 0x02 + XU_LATENCY_CONTROL = 0x03 + +class AudioStreamingInterfaceControlSelectors(IntEnum): + AS_CONTROL_UNDEFINED = 0x00 + AS_ACT_ALT_SETTING_CONTROL = 0x01 + AS_VAL_ALT_SETTINGS_CONTROL = 0x02 + AS_AUDIO_DATA_FORMAT_CONTROL = 0x03 + +class EndpointControlSelectors(IntEnum): + EP_CONTROL_UNDEFINED = 0x00 + EP_PITCH_CONTROL = 0x01 + EP_DATA_OVERRUN_CONTROL = 0x02 + EP_DATA_UNDERRUN_CONTROL = 0x03 + +###################### Terminal Types ######################### + +class USBTerminalTypes(IntEnum): + USB_UNDEFINED = 0x0100 + USB_STREAMING = 0x0101 + USB_VENDOR_SPECIFIC = 0x01FF + +class InputTerminalTypes(IntEnum): + INPUT_UNDEFINED = 0x0200 + MICROPHONE = 0x0201 + DESKTOP_MICROPHONE = 0x0202 + PERSONAL_MICROPHONE = 0x0203 + OMNI_DIRECTIONAL_MICROPHONE = 0x0204 + MICROPHONE_ARRAY = 0x0205 + PROCESSING_MICROPHONE_ARRAY = 0x0206 + +class OutputTerminalTypes(IntEnum): + OUTPUT_UNDEFINED = 0x0300 + SPEAKER = 0x0301 + HEADPHONES = 0x0302 + DESKTOP_SPEAKER = 0x0304 + ROOM_SPEAKER = 0x0305 + COMMUNICATION_SPEAKER = 0x0306 + LOW_FREQUENCY_EFFECTS_SPEAKER = 0x0307 + +class BidirectionalTerminalTypes(IntEnum): + BIDIRECTIONAL_UNDEFINED = 0x0400 + HANDSET = 0x0401 + HEADSET = 0x0402 + ECHO_SUPPRESSING_SPEAKERPHONE = 0x0404 + ECHO_CANCELING_SPEAKERPHONE = 0x0405 + +class TelephonyTerminalTypes(IntEnum): + TELEPHONY_UNDEFINED = 0x0500 + PHONE_LINE = 0x0501 + TELEPHONE = 0x0502 + DOWN_LINE_PHONE = 0x0503 + +class ExternalTerminalTypes(IntEnum): + EXTERNAL_UNDEFINED = 0x0600 + ANALOG_CONNECTOR = 0x0601 + DIGITAL_AUDIO_INTERFACE = 0x0602 + LINE_CONNECTOR = 0x0603 + SPDIF_INTERFACE = 0x0605 + IEEE_1394_DA_STREAM = 0x0606 + IEEE_1394_DV_STREAM_SOUNDTRACK = 0x0607 + ADAT_LIGHTPIPE = 0x0608 + TDIF = 0x0609 + MADI = 0x060A + +class EmbeddedFunctionTerminalTypes(IntEnum): + EMBEDDED_UNDEFINED = 0x0700 + EQUALIZATION_NOISE = 0x0702 + CD_PLAYER = 0x0703 + DAT = 0x0704 + DCC = 0x0705 + ANALOG_TAPE = 0x0707 + PHONOGRAPH = 0x0708 + VCR_AUDIO = 0x0709 + VIDEO_DISC_AUDIO = 0x070A + DVD_AUDIO = 0x070B + TV_TUNER_AUDIO = 0x070C + SATELLITE_RECEIVER_AUDIO = 0x070D + CABLE_TUNER_AUDIO = 0x070E + DSS_AUDIO = 0x070F + RADIO_RECEIVER = 0x0710 + RADIO_TRANSMITTER = 0x0711 + MULTI_TRACK_RECORDER = 0x0712 + SYNTHESIZER = 0x0713 + PIANO = 0x0714 + GUITAR = 0x0715 + DRUMS_RHYTHM = 0x0716 + OTHER_MUSICAL_INSTRUMENT = 0x0717 + +AudioControlInterruptEndpointDescriptor = DescriptorFormat( + "bLength" / construct.Const(7, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_ENDPOINT), + "bEndpointAddress" / DescriptorField(description="The address of the endpoint: D7: Direction (1 = IN); D6..4: Reserved; D3..0: endpoint number"), + "bmAttributes" / DescriptorField(description="D1..0: Transfer type (0b11 = Interrupt)", default=0b11), + "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of. Used here to pass 6-byte interrupt information.", default=6), + "bInterval" / DescriptorField(description="Interval for polling the Interrupt endpoint") +) + +AudioStreamingIsochronousEndpointDescriptor = DescriptorFormat( + "bLength" / construct.Const(7, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.ENDPOINT), + "bEndpointAddress" / DescriptorField(description="The address of the endpoint: D3..0: endpoint number; D6..4: Reserved; D7: direction (0=OUT / 1=IN)"), + "bmAttributes" / DescriptorField(description="D1..0: transfer type (01=isochronous); D3..2: synchronization type (01=asynchronous/10=adaptive/11=synchronous); D5..4: usage (00=data/10=feedback)", default=0b000101), + "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of. Used here to pass 6-byte interrupt information.", default=6), + "bInterval" / DescriptorField(description="Interval for polling the Interrupt endpoint") +) + +AudioStreamingIsochronousFeedbackEndpointDescriptor = DescriptorFormat( + "bLength" / construct.Const(7, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.ENDPOINT), + "bEndpointAddress" / DescriptorField(description="The address of the endpoint: D3..0: endpoint number; D6..4: Reserved; D7: direction (0=OUT / 1=IN)"), + "bmAttributes" / DescriptorField(description="D1..0: transfer type (01=isochronous); D3..2: synchronization type (00=no sync); D5..4: usage (10=feedback)", default=0b00100001), + "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of. Used here to pass 6-byte interrupt information.", default=6), + "bInterval" / DescriptorField(description="Interval for polling the Interrupt endpoint") +) diff --git a/usb_protocol/types/descriptors/uac2.py b/usb_protocol/types/descriptors/uac2.py new file mode 100644 index 0000000..341d3c8 --- /dev/null +++ b/usb_protocol/types/descriptors/uac2.py @@ -0,0 +1,306 @@ +# +# This file is part of usb-protocol. +# +""" descriptors specific to USB version 2 + NOTE: This is not complete yet and will be extended as needed +""" + +from build.lib.usb_protocol.emitters import descriptor +import unittest +from enum import IntEnum + +import construct +from construct import this, Default + +from .. import LanguageIDs +from ..descriptor import \ + DescriptorField, DescriptorNumber, DescriptorFormat, \ + BCDFieldAdapter, DescriptorLength + +from .uac import * + +class ClockAttributes(IntEnum): + EXTERNAL_CLOCK = 0b00 + INTERNAL_FIXED_CLOCK = 0b01 + INTERNAL_VARIABLE_CLOCK = 0b10 + INTERNAL_PROGRAMMABLE_CLOCK = 0b11 + +class ClockFrequencyControl(IntEnum): + NOT_PRESENT = 0b00 + HOST_READ_ONLY = 0b01 + HOST_PROGRAMMABLE = 0b11 + +class CopyProtectControl(IntEnum): + NOT_PRESENT = 0b00 + HOST_READ_ONLY = 0b10 + HOST_PROGRAMMABLE = 0b11 + +class ConnectorControl(IntEnum): + NOT_PRESENT = (0b00) << 2 + HOST_READ_ONLY = (0b10) << 2 + HOST_PROGRAMMABLE = (0b11) << 2 + +class OverloadControl(IntEnum): + NOT_PRESENT = (0b00) << 4 + HOST_READ_ONLY = (0b10) << 4 + HOST_PROGRAMMABLE = (0b11) << 4 + +class ClusterControl(IntEnum): + NOT_PRESENT = (0b00) << 6 + HOST_READ_ONLY = (0b10) << 6 + HOST_PROGRAMMABLE = (0b11) << 6 + +class UnderflowControl(IntEnum): + NOT_PRESENT = (0b00) << 8 + HOST_READ_ONLY = (0b10) << 8 + HOST_PROGRAMMABLE = (0b11) << 8 + +class OverflowControl(IntEnum): + NOT_PRESENT = (0b00) << 10 + HOST_READ_ONLY = (0b10) << 10 + HOST_PROGRAMMABLE = (0b11) << 10 + + +class FormatTypes(IntEnum): + FORMAT_TYPE_UNDEFINED = 0x00 + FORMAT_TYPE_I = 0x01 + FORMAT_TYPE_II = 0x02 + FORMAT_TYPE_III = 0x03 + FORMAT_TYPE_IV = 0x04 + EXT_FORMAT_TYPE_I = 0x81 + EXT_FORMAT_TYPE_II = 0x82 + EXT_FORMAT_TYPE_III = 0x83 + +class TypeIFormats(IntEnum): + PCM = (1 << 0) + PCM8 = (1 << 1) + IEEE_FLOAT = (1 << 2) + ALAW = (1 << 3) + MULAW = (1 << 4) + TYPE_I_RAW_DATA = (1 << 31) + +class TypeIIFormats(IntEnum): + MPEG = (1 << 0) + AC_3 = (1 << 1) + WMA = (1 << 2) + DTS = (1 << 3) + TYPE_II_RAW_DATA = (1 << 31) + +class TypeIIIFormats(IntEnum): + IEC61937_AC_3 = (1 << 0) + IEC61937_MPEG_1_Layer1 = (1 << 1) + IEC61937_MPEG_1_Layer2_3 = (1 << 2) # same bit! + IEC61937_MPEG_2_NOEXT = (1 << 2) # same bit! + IEC61937_MPEG_2_EXT = (1 << 3) + IEC61937_MPEG_2_AAC_ADTS = (1 << 4) + IEC61937_MPEG_2_Layer1_LS = (1 << 5) + IEC61937_MPEG_2_Layer2_3_LS = (1 << 6) + IEC61937_DTS_I = (1 << 7) + IEC61937_DTS_II = (1 << 8) + IEC61937_DTS_III = (1 << 9) + IEC61937_ATRAC = (1 << 10) + IEC61937_ATRAC2_3 = (1 << 11) + TYPE_III_WMA = (1 << 12) + +class TypeIVFormats(IntEnum): + PCM = (1 << 0) + PCM8 = (1 << 1) + IEEE_FLOAT = (1 << 2) + ALAW = (1 << 3) + MULAW = (1 << 4) + MPEG = (1 << 5) + AC_3 = (1 << 6) + WMA = (1 << 7) + IEC61937_AC_3 = (1 << 8) + IEC61937_MPEG_1_Layer1 = (1 << 9) + IEC61937_MPEG_1_Layer2_3 = (1 << 10) # same bit! + IEC61937_MPEG_2_NOEXT = (1 << 10) # same bit! + IEC61937_MPEG_2_EXT = (1 << 11) + IEC61937_MPEG_2_AAC_ADTS = (1 << 12) + IEC61937_MPEG_2_Layer1_LS = (1 << 13) + IEC61937_MPEG_2_Layer2_3_LS = (1 << 14) + IEC61937_DTS_I = (1 << 15) + IEC61937_DTS_II = (1 << 16) + IEC61937_DTS_III = (1 << 17) + IEC61937_ATRAC = (1 << 18) + IEC61937_ATRAC2_3 = (1 << 19) + TYPE_III_WMA = (1 << 20) + IEC60958_PCM = (1 << 21) + +class SidebandProtocols(IntEnum): + PROTOCOL_UNDEFINED = 0x00 + PRES_TIMESTAMP_PROTOCOL = 0x02 + +class AudioClassSpecificASInterfaceDescriptorSubtypes(IntEnum): + AS_DESCRIPTOR_UNDEFINED = 0x00 + AS_GENERAL = 0x01 + FORMAT_TYPE = 0x02 + ENCODER = 0x03 + DECODER = 0x04 + +InterfaceAssociationDescriptor = DescriptorFormat( + "bLength" / construct.Const(8, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.INTERFACE_ASSOCIATION), + "bFirstInterface" / DescriptorField(description="Interface number of the first interface that is associated with this function.", default=0), + "bInterfaceCount" / DescriptorField(description="Number of contiguous interfaces that are associated with this function"), + "bFunctionClass" / DescriptorNumber(AudioFunctionClassCode.AUDIO_FUNCTION), + "bFunctionSubClass" / DescriptorField(description="function subclass code (currently not used in uac2)", default=AudioFunctionCategoryCodes.FUNCTION_SUBCLASS_UNDEFINED), + "bFunctionProtocol" / DescriptorNumber(AudioFunctionProtocolCodes.AF_VERSION_02_00), + "iFunction" / DescriptorField(description="Index of a string descriptor that describes this interface", default=0), +) + +StandardAudioControlInterfaceDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.INTERFACE), + "bAlternateSetting" / DescriptorField(description="alternate setting for the interface (must be 0)", default=0), + "bNumEndpoints" / DescriptorField(description="number of endpoints used by this interface (excluding endpoint 0). This number is either 0 or 1 if the optional interrupt endpoint is present", default=0), + "bInterfaceClass" / DescriptorNumber(AudioInterfaceClassCode.AUDIO), + "bInterfaceSubClass" / DescriptorNumber(AudioInterfaceSubclassCodes.AUDIO_CONTROL), + "bInterfaceProtocol" / DescriptorNumber(AudioInterfaceProtocolCodes.IP_VERSION_02_00), + "iInterface" / DescriptorField(description="index of string descriptor describing this interface", default=0), +) + +ClassSpecificAudioControlInterfaceDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.HEADER), + "bcdADC" / DescriptorField(description="Audio Device Class specification release version", default=2.0), + "bCategory" / DescriptorField(description="primary use of this audio function (see AudioFunctionCategoryCodes)", default=AudioFunctionCategoryCodes.IO_BOX), + "wTotalLength" / DescriptorField(description="total number of bytes for the class specific audio control interface descriptor; Includes the combined length of this descriptor header and all Clock Source, Unit and Terminal descriptors"), + "bmControls" / DescriptorField(description="D1..0: latency control", default=0), +) + +ClockSourceDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.CLOCK_SOURCE), + "bClockID" / DescriptorField(description="ID of the clock source entity within the audio function (used in requests)"), + "bmAttributes" / DescriptorField(description="D1..0: clock type (see ClockAttributs)"), + "bmControls" / DescriptorField(description="D1..0: clock frequency control (D0..1: See ClockFrequencyControl, D3..2: clock validity control (0))", default=ClockFrequencyControl.NOT_PRESENT), + "bAssocTerminal" / DescriptorField(description="ID of the terminal which is associated with this clock", default=0), + "iClockSource" / DescriptorField(description="index of the string description of this clock source", default=0), +) + +InputTerminalDescriptor = DescriptorFormat( + "bLength" / construct.Const(17, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.INPUT_TERMINAL), + "bTerminalID" / DescriptorField(description="unique identifier for the terminal within the audio function (used in requests)"), + "wTerminalType" / DescriptorField(description="a value of one of the terminal types Enums (eg InputTerminaTypes, ExternalTerminalTypes)"), + "bAssocTerminal" / DescriptorField(description="ID of the associated output terminal", default=0), + "bCSourceID" / DescriptorField(description="ID of the clock which is connected to this terminal"), + "bNrChannels" / DescriptorField(description="number of logical output channels in the terminal’s output channel cluster"), + "bmChannelConfig" / DescriptorField(description="describes the spatial location of the logical channels", default=0), + "bmControls" / DescriptorField(description="OR combination of ClockFrequencyControl, CopyProtectControl, ConnectorControl, ClusterControl, UnderflowControl and OverflowControl", default=0), + "iChannelNames" / DescriptorField(description="string descriptor index of the first logical channel name", default=0), + "iTerminal" / DescriptorField(description="ID of the input terminal string description", default=0) +) + +OutputTerminalDescriptor = DescriptorFormat( + "bLength" / construct.Const(12, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.OUTPUT_TERMINAL), + "bTerminalID" / DescriptorField(description="unique identifier for the terminal within the audio function."), + "wTerminalType" / DescriptorField(description="a value of one of the terminal types Enums (eg OutputTerminaTypes, ExternalTerminalTypes)"), + "bAssocTerminal" / DescriptorField(description="ID of the associated input terminal", default=0), + "bSourceID" / DescriptorField(description="ID of the unit or terminal which is connected to this terminal"), + "bCSourceID" / DescriptorField(description="ID of the clock which is connected to this terminal"), + "bmControls" / DescriptorField(description="OR combination of ClockFrequencyControl, CopyProtectControl, ConnectorControl, UnderflowControl>>2 and OverflowControl>>2", default=0), + "iTerminal" / DescriptorField(description="ID of the input terminal string description", default=0) +) + +AudioStreamingInterfaceDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.INTERFACE), + "bInterfaceNumber" / DescriptorField(description="ID of the streaming interface"), + "bAlternateSetting" / DescriptorField(description="alternate setting number for the interface", default=0), + "bNumEndpoints" / DescriptorField(description="Number of data endpoints used (excluding endpoint 0). Can be: 0 (no data endpoint); 1 (data endpoint); 2 (data + explicit feedback endpoint)", default=0), + "bInterfaceClass" / DescriptorNumber(AudioInterfaceClassCode.AUDIO), + "bInterfaceSubClass" / DescriptorNumber(AudioInterfaceSubclassCodes.AUDIO_STREAMING), + "bInterfaceProtocol" / DescriptorNumber(AudioInterfaceProtocolCodes.IP_VERSION_02_00), + "iInterface" / DescriptorField(description="index of a string descriptor describing this interface (0 = unused)", default=0) +) + +ClassSpecificAudioStreamingInterfaceDescriptor = DescriptorFormat( + "bLength" / construct.Const(16, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.AS_GENERAL), + "bTerminalLink" / DescriptorField(description="the ID of the terminal to which this interface is connected"), + "bmControls" / DescriptorField(description="D1..0: active alternate setting control; D3..2: valid alternate settings control; D7..4: reserved, must be 0", default=0), + "bFormatType" / DescriptorField(description="see FormatTypes"), + "bmFormats" / DescriptorField(description="audio data formats which can be used with this interface", length=4), + "bNrChannels" / DescriptorField(description="Number of physical channels in the AS Interface audio channel cluster"), + "bmChannelConfig" / DescriptorField(description="spatial location of the physical channels", default=0), + "iChannelNames" / DescriptorField(description="ndex of a string descriptor, describing the name of the first physical channel.", default=0) +) + +TypeIFormatTypeDescriptor = DescriptorFormat( + "bLength" / construct.Const(6, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.FORMAT_TYPE), + "bFormatType" / DescriptorNumber(FormatTypes.FORMAT_TYPE_I), + "bSubslotSize" / DescriptorField(description="number of bytes occupied by one audio subslot (1, 2, 3 or 4)"), + "bBitResolution" / DescriptorField(description="number of effectively used bits out of the available bits in an audio subslot") +) + +ExtendedTypeIFormatTypeDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.FORMAT_TYPE), + "bFormatType" / DescriptorNumber(FormatTypes.EXT_FORMAT_TYPE_I), + "bSubslotSize" / DescriptorField(description="number of bytes occupied by one audio subslot (1, 2, 3 or 4)"), + "bBitResolution" / DescriptorField(description="number of effectively used bits out of the available bits in an audio subslot"), + "bHeaderLength" / DescriptorField(description="size of the packet header in bytes"), + "bControlSize" / DescriptorField(description="size of the control channel words in bytes"), + "bSideBandProtocol" / DescriptorField(description="side band protocol, see SidebandProtocols", default=SidebandProtocols.PROTOCOL_UNDEFINED) +) + +TypeIIFormatTypeDescriptor = DescriptorFormat( + "bLength" / construct.Const(8, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.FORMAT_TYPE), + "bFormatType" / DescriptorNumber(FormatTypes.FORMAT_TYPE_II), + "wMaxBitRate" / DescriptorField(description="maximum bitrate of this interface in kbits/s"), + "wSlotsPerFrame" / DescriptorField(description="number of PCM audio slots in one audio frame") +) + +ExtendedTypeIIFormatTypeDescriptor = DescriptorFormat( + "bLength" / construct.Const(10, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.FORMAT_TYPE), + "bFormatType" / DescriptorNumber(FormatTypes.EXT_FORMAT_TYPE_II), + "wMaxBitRate" / DescriptorField(description="maximum bitrate of this interface in kbits/s"), + "wSamplesPerFrame" / DescriptorField(description="number of PCM audio samples in one audio frame"), + "bHeaderLength" / DescriptorField(description="size of the packet header in bytes"), + "bSideBandProtocol" / DescriptorField(description="side band protocol, see SidebandProtocols", default=SidebandProtocols.PROTOCOL_UNDEFINED) +) + +TypeIIIFormatTypeDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.FORMAT_TYPE), + "bFormatType" / DescriptorNumber(FormatTypes.FORMAT_TYPE_III), + "bSubslotSize" / DescriptorField(description="number of bytes occupied by one audio subslot (must be 2)", default=2), + "bBitResolution" / DescriptorField(description="number of effectively used bits out of the available bits in an audio subslot"), +) + +ExtendedTypeIIIFormatTypeDescriptor = DescriptorFormat( + "bLength" / construct.Const(8, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.FORMAT_TYPE), + "bFormatType" / DescriptorNumber(FormatTypes.EXT_FORMAT_TYPE_III), + "bSubslotSize" / DescriptorField(description="number of bytes occupied by one audio subslot (must be 2)", default=2), + "bBitResolution" / DescriptorField(description="number of effectively used bits out of the available bits in an audio subslot"), + "bHeaderLength" / DescriptorField(description="size of the packet header in bytes"), + "bSideBandProtocol" / DescriptorField(description="side band protocol, see SidebandProtocols", default=SidebandProtocols.PROTOCOL_UNDEFINED) +) + +ClassSpecificAudioStreamingIsochronousAudioDataEndpointDescriptor = DescriptorFormat( + "bLength" / construct.Const(8, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_ENDPOINT), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificEndpointDescriptorSubtypes.EP_GENERAL), + "bmAttributes" / DescriptorField(description="bit D7 = 1: only packets with size wMaxPacketSize allowed", default=0), + "bmControls" / DescriptorField(description="D1..0: pitch control D3..2: data overrun control; D5..4: data underrun control;", default=0), + "bLockDelayUnits" / DescriptorField(description="wLockDelay unit: 0: undefined; 1: milliseconds; 2: decoded PCM samples;", default=0), + "wLockDelay" / DescriptorField(description="the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units see bLockDelayUnits", default=0) +) \ No newline at end of file diff --git a/usb_protocol/types/descriptors/uac3.py b/usb_protocol/types/descriptors/uac3.py new file mode 100644 index 0000000..e065c5e --- /dev/null +++ b/usb_protocol/types/descriptors/uac3.py @@ -0,0 +1,167 @@ +# +# This file is part of usb-protocol. +# +""" + descriptors specific to USB version 2 + NOTE: This is not complete yet and will be extended as needed +""" + +from build.lib.usb_protocol.emitters import descriptor +import unittest +from enum import IntEnum + +import construct +from construct import this, Default + +from .. import LanguageIDs +from ..descriptor import \ + DescriptorField, DescriptorNumber, DescriptorFormat, \ + BCDFieldAdapter, DescriptorLength + +from .uac import * + +class AudioClassSpecificASInterfaceDescriptorSubtypes(IntEnum): + AS_DESCRIPTOR_UNDEFINED = 0x00 + AS_GENERAL = 0x01 + AS_VALID_FREQ_RANGE = 0x02 + +class ConnectorTypess(IntEnum): + UNDEFINED = 0x00 + PHONE_CONNECTOR_2_5_MM = 0x01 + PHONE_CONNECTOR_3_5_MM = 0x02 + PHONE_CONNECTOR_6_35_MM = 0x03 + XLR_6_35MM_COMBO_CONNECTOR = 0x04 + XLR = 0x05 + OPTICAL_3_5MM_COMBO_CONNECTOR = 0x06 + RCA = 0x07 + BNC = 0x08 + BANANA = 0x09 + BINDING_POST = 0x0A + SPEAKON = 0x0B + SPRING_CLIP = 0x0C + SCREW_TYPE = 0x0D + DIN = 0x0E + MINI_DIN = 0x0F + EUROBLOCK = 0x10 + USB_TYPE_C = 0x11 + RJ_11 = 0x12 + RJ_45 = 0x13 + TOSLINK = 0x14 + HDMI = 0x15 + Mini_HDMI = 0x16 + Micro_HDMI = 0x17 + DP = 0x18 + MINI_DP = 0x19 + D_SUB = 0x1A + THUNDERBOLT = 0x1B + LIGHTNING = 0x1C + WIRELESS = 0x1D + USB_STANDARD_A = 0x1E + USB_STANDARD_B = 0x1F + USB_MINI_B = 0x20 + USB_MICRO_B = 0x21 + USB_MICRO_AB = 0x22 + USB_3_0_MICRO_B = 0x23 + +class AudioDataFormats(IntEnum): + PCM = (1 << 0) + PCM8 = (1 << 1) + IEEE_FLOAT = (1 << 2) + ALAW = (1 << 3) + MULAW = (1 << 4) + DSD = (1 << 5) + RAW_DATA = (1 << 6) + PCM_IEC60958 = (1 << 7) + AC_3 = (1 << 8) + MPEG_1_Layer1 = (1 << 9) + MPEG_1_Layer2_3 = (1 << 10) # These share the same bit + MPEG_2_NOEXT = (1 << 10) # These share the same bit + MPEG_2_EXT = (1 << 11) + MPEG_2_AAC_ADTS = (1 << 12) + MPEG_2_Layer1_LS = (1 << 13) + MPEG_2_Layer2_3_LS = (1 << 14) + DTS_I = (1 << 15) + DTS_II = (1 << 16) + DTS_III = (1 << 17) + ATRAC = (1 << 18) + ATRAC2_3 = (1 << 19) + WMA = (1 << 20) + E_AC_3 = (1 << 21) + MAT = (1 << 22) + DTS_IV = (1 << 23) + MPEG_4_HE_AAC = (1 << 24) + MPEG_4_HE_AAC_V2 = (1 << 25) + MPEG_4_AAC_LC = (1 << 26) + DRA = (1 << 27) + MPEG_4_HE_AAC_SURROUND = (1 << 28) + MPEG_4_AAC_LC_SURROUND = (1 << 29) + MPEG_H_3D_AUDIO = (1 << 30) + AC4 = (1 << 31) + MPEG_4_AAC_ELD = (1 << 32) + + +HeaderDescriptor = DescriptorFormat( + "bLength" / construct.Const(10, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.HEADER), + "bCategory" / DescriptorField(description="Audio Function Category, see AudioFunctionCategoryCodes"), + "wTotalLength" / DescriptorField("Length including subordinates"), + "bmControls" / DescriptorField("D1..0: Latency Control; D31..2: Reserved.", length=4, default=0) +) + +AudioStreamingInterfaceDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.INTERFACE), + "bInterfaceNumber" / DescriptorField(description="ID of the streaming interface"), + "bAlternateSetting" / DescriptorField(description="alternate setting number for the interface", default=0), + "bNumEndpoints" / DescriptorField(description="Number of data endpoints used (excluding endpoint 0). Can be: 0 (no data endpoint); 1 (data endpoint); 2 (data + explicit feedback endpoint)", default=0), + "bInterfaceClass" / DescriptorNumber(AudioInterfaceClassCode.AUDIO), + "bInterfaceSubClass" / DescriptorNumber(AudioInterfaceSubclassCodes.AUDIO_STREAMING), + "bInterfaceProtocol" / DescriptorNumber(AudioInterfaceProtocolCodes.IP_VERSION_03_00), + "iInterface" / DescriptorField(description="index of a string descriptor describing this interface (0 = unused)") +) + +ClassSpecificAudioStreamingInterfaceDescriptor = DescriptorFormat( + "bLength" / construct.Const(23, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificASInterfaceDescriptorSubtypes.AS_GENERAL), + "bTerminalLink" / DescriptorField(description="the ID of the terminal to which this interface is connected"), + "bmControls" / DescriptorField(description="D1..0: active alternate setting control; D3..2: valid alternate settings control; D5..4: audio data format control; D31..6: reserved"), + "wClusterDescrID" / DescriptorField(description="ID of the cluster descriptor of the audio streamin interface"), + "bmFormats" / DescriptorField(description="audio data formats which can be used with this interface", length=8, default=AudioDataFormats.PCM), + "bSubslotSize" / DescriptorField(description="number of bytes occupied by one audio subslot"), + "bBitResolution" / DescriptorField(description="number of effectively used bits in the audio subslot"), + "bmAuxProtocols" / DescriptorField(description="which auxiliary protocols are required", default=0), + "bControlSize" / DescriptorField(description="size of the control channel words in bytes") +) + +InputTerminalDescriptor = DescriptorFormat( + "bLength" / construct.Const(20, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.INPUT_TERMINAL), + "bTerminalID" / DescriptorField(description="unique identifier for the terminal within the audio function."), + "wTerminalType" / DescriptorField(description="a value of one of the terminal types Enums (eg InputTerminaTypes, ExternalTerminalTypes)"), + "bAssocTerminal" / DescriptorField(description="ID of the associated output terminal"), + "bCSourceID" / DescriptorField(description="ID of the clock which is connected to this terminal"), + "bmControls" / DescriptorField(description="D1..0: Insertion Control; D3..2: Overload Control; D5..4: Underflow Control; D7..6: Overflow Control; D31..8: Reserved"), + "wClusterDescrID" / DescriptorField(description="ID of the cluster descriptor for this input terminal."), + "wExTerminalDescrID" / DescriptorField(description="ID of the extended terminal descriptor for this input terminal. Zero if no extended terminal descriptor is present."), + "wConnectorsDescrID" / DescriptorField(description="ID of the Connectors descriptor for this Input Terminal. Zero if no connectors descriptor is present."), + "wTerminalDescrStr" / DescriptorField(description="ID of a class-specific string descriptor, describing the input terminal.") +) + +OutputTerminalDescriptor = DescriptorFormat( + "bLength" / construct.Const(19, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.OUTPUT_TERMINAL), + "bTerminalID" / DescriptorField(description="unique identifier for the terminal within the audio function."), + "wTerminalType" / DescriptorField(description="a value of one of the terminal types Enums (eg OutputTerminaTypes, ExternalTerminalTypes)"), + "bAssocTerminal" / DescriptorField(description="ID of the associated input terminal"), + "bSourceID" / DescriptorField(description="ID of the unit or terminal which is connected to this terminal"), + "bCSourceID" / DescriptorField(description="ID of the clock which is connected to this terminal"), + "bmControls" / DescriptorField(description="D1..0: Insertion Control; D3..2: Overload Control; D5..4: Underflow Control; D7..6: Overflow Control; D31..8: Reserved"), + "wClusterDescrID" / DescriptorField(description="ID of the cluster descriptor for this input terminal."), + "wExTerminalDescrID" / DescriptorField(description="ID of the extended terminal descriptor for this output terminal. Zero if no extended terminal descriptor is present.", default=0), + "wConnectorsDescrID" / DescriptorField(description="ID of the connectors descriptor for this input terminal. Zero if no connectors descriptor is present.", default=0), + "wTerminalDescrStr" / DescriptorField(description="ID of a class-specific string descriptor, describing the output terminal.") +) \ No newline at end of file From 5ad0368097876a349c2fae14e0a411559f5d9e2d Mon Sep 17 00:00:00 2001 From: Hans Baier Date: Sat, 6 Mar 2021 04:42:41 +0700 Subject: [PATCH 2/2] add MIDI Streaming Descriptors --- usb_protocol/emitters/descriptors/uac.py | 67 ++++++++++++ usb_protocol/emitters/descriptors/uac2.py | 4 +- usb_protocol/types/descriptors/uac.py | 124 ++++++++++++++++++++-- usb_protocol/types/descriptors/uac2.py | 51 +++++++-- 4 files changed, 228 insertions(+), 18 deletions(-) create mode 100644 usb_protocol/emitters/descriptors/uac.py diff --git a/usb_protocol/emitters/descriptors/uac.py b/usb_protocol/emitters/descriptors/uac.py new file mode 100644 index 0000000..0798e87 --- /dev/null +++ b/usb_protocol/emitters/descriptors/uac.py @@ -0,0 +1,67 @@ +# +# This file is part of usb_protocol. +# +""" Convenience emitters for USB Audio Class 2 descriptors. """ + +from contextlib import contextmanager + +from .. import emitter_for_format +from ...types.descriptors.uac import * +from ...types.descriptors.uac2 import * +from ...emitters.descriptor import ComplexDescriptorEmitter + +###################### MIDI ######################### + +StandardMidiStreamingInterfaceDescriptorEmitter = emitter_for_format(StandardMidiStreamingInterfaceDescriptor) +ClassSpecificMidiStreamingInterfaceHeaderDescriptorEmitter = emitter_for_format(ClassSpecificMidiStreamingInterfaceHeaderDescriptor) +StandardMidiStreamingDataEndpointDescriptorEmitter = emitter_for_format(StandardMidiStreamingDataEndpointDescriptor) +StandardMidiStreamingBulkDataEndpointDescriptorEmitter = emitter_for_format(StandardMidiStreamingBulkDataEndpointDescriptor) +MidiInJackDescriptorEmitter = emitter_for_format(MidiInJackDescriptor) +MidiOutJackDescriptorElementEmitter = emitter_for_format(MidiOutJackDescriptorElement) +MidiOutJackDescriptorFootEmitter = emitter_for_format(MidiOutJackDescriptorFoot) +ClassSpecificMidiStreamingBulkDataEndpointDescriptorHeadEmitter = emitter_for_format(ClassSpecificMidiStreamingBulkDataEndpointDescriptorHead) +ClassSpecificMidiStreamingBulkDataEndpointDescriptorElementEmitter = emitter_for_format(ClassSpecificMidiStreamingBulkDataEndpointDescriptorElement) + +class ClassSpecificMidiStreamingInterfaceDescriptorEmitter(ComplexDescriptorEmitter): + DESCRIPTOR_FORMAT = ClassSpecificMidiStreamingInterfaceHeaderDescriptor + + def _pre_emit(self): + # Figure out the total length of our descriptor, including subordinates. + subordinate_length = sum(len(sub) for sub in self._subordinates) + self.wTotalLength = subordinate_length + self.DESCRIPTOR_FORMAT.sizeof() + +class MidiOutJackDescriptorEmitter(ComplexDescriptorEmitter): + DESCRIPTOR_FORMAT = MidiOutJackDescriptorHead + + def add_subordinate_descriptor(self, subordinate): + subordinate = subordinate.emit() + self._subordinates.append(subordinate) + + def add_source(self, sourceId, sourcePin=1): + sourceDescriptor = MidiOutJackDescriptorElementEmitter() + sourceDescriptor.baSourceID = sourceId + sourceDescriptor.BaSourcePin = sourcePin + self.add_subordinate_descriptor(sourceDescriptor) + + def _pre_emit(self): + self.add_subordinate_descriptor(MidiOutJackDescriptorFootEmitter()) + # Figure out the total length of our descriptor, including subordinates. + subordinate_length = sum(len(sub) for sub in self._subordinates) + self.bLength = subordinate_length + self.DESCRIPTOR_FORMAT.sizeof() + +class ClassSpecificMidiStreamingBulkDataEndpointDescriptorEmitter(ComplexDescriptorEmitter): + DESCRIPTOR_FORMAT = ClassSpecificMidiStreamingBulkDataEndpointDescriptorHead + + def add_subordinate_descriptor(self, subordinate): + subordinate = subordinate.emit() + self._subordinates.append(subordinate) + + def add_associated_jack(self, jackID): + jackDescriptor = ClassSpecificMidiStreamingBulkDataEndpointDescriptorElementEmitter() + jackDescriptor.baAssocJackID = jackID + self.add_subordinate_descriptor(jackDescriptor) + + def _pre_emit(self): + # Figure out the total length of our descriptor, including subordinates. + subordinate_length = sum(len(sub) for sub in self._subordinates) + self.bLength = subordinate_length + self.DESCRIPTOR_FORMAT.sizeof() \ No newline at end of file diff --git a/usb_protocol/emitters/descriptors/uac2.py b/usb_protocol/emitters/descriptors/uac2.py index d15bd4e..4a46009 100644 --- a/usb_protocol/emitters/descriptors/uac2.py +++ b/usb_protocol/emitters/descriptors/uac2.py @@ -10,6 +10,8 @@ from ...types.descriptors.uac import * from ...types.descriptors.uac2 import * from ...emitters.descriptor import ComplexDescriptorEmitter +###################### Audio ######################### + # Create our emitters. InterfaceAssociationDescriptorEmitter = emitter_for_format(InterfaceAssociationDescriptor) StandardAudioControlInterfaceDescriptorEmitter = emitter_for_format(StandardAudioControlInterfaceDescriptor) @@ -36,4 +38,4 @@ ExtendedTypeIIIFormatTypeDescriptorEmitter = emitt ClassSpecificAudioStreamingIsochronousAudioDataEndpointDescriptorEmitter = emitter_for_format(ClassSpecificAudioStreamingIsochronousAudioDataEndpointDescriptor) AudioControlInterruptEndpointDescriptorEmitter = emitter_for_format(AudioControlInterruptEndpointDescriptor) AudioStreamingIsochronousEndpointDescriptorEmitter = emitter_for_format(AudioStreamingIsochronousEndpointDescriptor) -AudioStreamingIsochronousFeedbackEndpointDescriptorEmitter = emitter_for_format(AudioStreamingIsochronousFeedbackEndpointDescriptor) +AudioStreamingIsochronousFeedbackEndpointDescriptorEmitter = emitter_for_format(AudioStreamingIsochronousFeedbackEndpointDescriptor) \ No newline at end of file diff --git a/usb_protocol/types/descriptors/uac.py b/usb_protocol/types/descriptors/uac.py index 796dec3..497a5a6 100644 --- a/usb_protocol/types/descriptors/uac.py +++ b/usb_protocol/types/descriptors/uac.py @@ -3,17 +3,14 @@ # """ common USB audio enums and descriptors """ -from build.lib.usb_protocol.emitters import descriptor -import unittest +from usb_protocol.types import USBSynchronizationType, USBUsageType from enum import IntEnum import construct -from construct import this, Default -from .. import LanguageIDs +from .. import USBTransferType from ..descriptor import \ - DescriptorField, DescriptorNumber, DescriptorFormat, \ - BCDFieldAdapter, DescriptorLength + DescriptorField, DescriptorNumber, DescriptorFormat class AudioInterfaceClassCode(IntEnum): AUDIO = 0x01 @@ -396,7 +393,7 @@ class EmbeddedFunctionTerminalTypes(IntEnum): AudioControlInterruptEndpointDescriptor = DescriptorFormat( "bLength" / construct.Const(7, construct.Int8ul), "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_ENDPOINT), - "bEndpointAddress" / DescriptorField(description="The address of the endpoint: D7: Direction (1 = IN); D6..4: Reserved; D3..0: endpoint number"), + "bEndpointAddress" / DescriptorField(description="The address of the endpoint, use USBDirection.*.from_endpoint_address()"), "bmAttributes" / DescriptorField(description="D1..0: Transfer type (0b11 = Interrupt)", default=0b11), "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of. Used here to pass 6-byte interrupt information.", default=6), "bInterval" / DescriptorField(description="Interval for polling the Interrupt endpoint") @@ -405,7 +402,7 @@ AudioControlInterruptEndpointDescriptor = DescriptorFormat( AudioStreamingIsochronousEndpointDescriptor = DescriptorFormat( "bLength" / construct.Const(7, construct.Int8ul), "bDescriptorType" / DescriptorNumber(DescriptorTypes.ENDPOINT), - "bEndpointAddress" / DescriptorField(description="The address of the endpoint: D3..0: endpoint number; D6..4: Reserved; D7: direction (0=OUT / 1=IN)"), + "bEndpointAddress" / DescriptorField(description="The address of the endpoint, use USBDirection.*.from_endpoint_address()"), "bmAttributes" / DescriptorField(description="D1..0: transfer type (01=isochronous); D3..2: synchronization type (01=asynchronous/10=adaptive/11=synchronous); D5..4: usage (00=data/10=feedback)", default=0b000101), "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of. Used here to pass 6-byte interrupt information.", default=6), "bInterval" / DescriptorField(description="Interval for polling the Interrupt endpoint") @@ -414,8 +411,117 @@ AudioStreamingIsochronousEndpointDescriptor = DescriptorFormat( AudioStreamingIsochronousFeedbackEndpointDescriptor = DescriptorFormat( "bLength" / construct.Const(7, construct.Int8ul), "bDescriptorType" / DescriptorNumber(DescriptorTypes.ENDPOINT), - "bEndpointAddress" / DescriptorField(description="The address of the endpoint: D3..0: endpoint number; D6..4: Reserved; D7: direction (0=OUT / 1=IN)"), + "bEndpointAddress" / DescriptorField(description="The address of the endpoint, use USBDirection.*.from_endpoint_address()"), "bmAttributes" / DescriptorField(description="D1..0: transfer type (01=isochronous); D3..2: synchronization type (00=no sync); D5..4: usage (10=feedback)", default=0b00100001), "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of. Used here to pass 6-byte interrupt information.", default=6), "bInterval" / DescriptorField(description="Interval for polling the Interrupt endpoint") ) + +###################### MIDI ######################### +class MidiStreamingInterfaceDescriptorTypes(IntEnum): + CS_UNDEFINED = 0x20 + CS_DEVICE = 0x21 + CS_CONFIGURATION = 0x22 + CS_STRING = 0x23 + CS_INTERFACE = 0x24 + CS_ENDPOINT = 0x25 + CS_GR_TRM_BLOCK = 0x26 + +class MidiStreamingInterfaceDescriptorSubtypes(IntEnum): + MS_DESCRIPTOR_UNDEFINED = 0x00 + MS_HEADER = 0x01 + MIDI_IN_JACK = 0x02 + MIDI_OUT_JACK = 0x03 + ELEMENT = 0x04 + +class MidiStreamingEndpointDescriptorSubtypes(IntEnum): + DESCRIPTOR_UNDEFINED = 0x00 + MS_GENERAL = 0x01 + MS_GENERAL_2_0 = 0x02 + +class MidiStreamingInterfaceHeaderClassRevision(IntEnum): + MS_MIDI_1_0 = 0x0100 + MS_MIDI_2_0 = 0x0200 + +class MidiStreamingJackTypes(IntEnum): + JACK_TYPE_UNDEFINED = 0x00 + EMBEDDED = 0x01 + EXTERNAL = 0x02 + +StandardMidiStreamingInterfaceDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.INTERFACE), + "bInterfaceNumber" / DescriptorField(description="ID of the streaming interface"), + "bAlternateSetting" / DescriptorField(description="alternate setting number for the interface", default=0), + "bNumEndpoints" / DescriptorField(description="Number of data endpoints used (excluding endpoint 0). Can be: 0 (no data endpoint); 1 (data endpoint); 2 (data + explicit feedback endpoint)", default=0), + "bInterfaceClass" / DescriptorNumber(AudioInterfaceClassCode.AUDIO), + "bInterfaceSubClass" / DescriptorNumber(AudioInterfaceSubclassCodes.MIDI_STREAMING), + "bInterfaceProtocol" / DescriptorNumber(0), + "iInterface" / DescriptorField(description="index of a string descriptor describing this interface (0 = unused)", default=0) +) + +ClassSpecificMidiStreamingInterfaceHeaderDescriptor = DescriptorFormat( + "bLength" / construct.Const(7, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.HEADER), + "bcdADC" / DescriptorField(description="Midi Streaming Class specification release version", default=1.0), + "wTotalLength" / DescriptorField(description="Total number of bytes of the class-specific MIDIStreaming interface descriptor. Includes the combined length of this descriptor header and all Jack and Element descriptors."), +) + +StandardMidiStreamingDataEndpointDescriptor = DescriptorFormat( + "bLength" / construct.Const(7, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_ENDPOINT), + "bEndpointAddress" / DescriptorField(description="endpoint address, use USBDirection.*.from_endpoint_address()"), + "bmAttributes" / DescriptorField(description="endpoint type, see USBTransferType (only NONE, BULK or INTERRUPT allowed)", default=USBTransferType.BULK), + "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of sending or receiving"), + "bInterval" / DescriptorField(description="Interval for polling endpoint for Interrupt data transfers. For bulk endpoints this field is ignored and must be reset to 0", default=0) +) + +MidiInJackDescriptor = DescriptorFormat( + "bLength" / construct.Const(6, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(MidiStreamingInterfaceDescriptorSubtypes.MIDI_IN_JACK), + "bJackType" / DescriptorField(description="see MidiStreamingJackTypes"), + "bJackID" / DescriptorField(description="Constant uniquely identifying the MIDI IN Jack within the USB-MIDI function"), + "iJack" / DescriptorField(description="index of a string descriptor describing this jack (0 = unused)", default=0) +) + +MidiOutJackDescriptorHead = DescriptorFormat( + "bLength" / DescriptorField(description="Size of this descriptor, in bytes: 6+2*p"), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_INTERFACE), + "bDescriptorSubtype" / DescriptorNumber(MidiStreamingInterfaceDescriptorSubtypes.MIDI_OUT_JACK), + "bJackType" / DescriptorField(description="see MidiStreamingJackTypes"), + "bJackID" / DescriptorField(description="Constant uniquely identifying the MIDI IN Jack within the USB-MIDI function"), + "bNrInputPins" / DescriptorField(description="Number of Input Pins of this MIDI OUT Jack: p", default=1) +) + +MidiOutJackDescriptorElement = DescriptorFormat( + "baSourceID" / construct.Int8ul, # ID of the Entity to which the first Input Pin of this MIDI OUT Jack is connected + "BaSourcePin" / construct.Int8ul, #Output Pin number of the Entity to which the first Input Pin of this MIDI OUT Jack is connected +) + +MidiOutJackDescriptorFoot = DescriptorFormat( + "iJack" / DescriptorField(description="index of a string descriptor describing this jack (0 = unused)", default=0) +) + +StandardMidiStreamingBulkDataEndpointDescriptor = DescriptorFormat( + "bLength" / construct.Const(9, construct.Int8ul), + "bDescriptorType" / DescriptorNumber(DescriptorTypes.ENDPOINT), + "bEndpointAddress" / DescriptorField(description="The address of the endpoint, use USBDirection.*.from_endpoint_address()"), + "bmAttributes" / DescriptorField(description="D1..0: transfer type (10=bulk), D3..2: synchronization type (00=no sync);", default=USBTransferType.BULK | USBSynchronizationType.NONE | USBUsageType.DATA), + "wMaxPacketSize" / DescriptorField(description="Maximum packet size this endpoint is capable of", default=512), + "bInterval" / DescriptorField(description="Interval for polling endpoint for data transfers expressed in milliseconds. This field is ignored for bulk endpoints. Must be set to 0", default=0), + "bRefresh" / DescriptorField(description="must be set to 0", default=0), + "bSynchAddress" / DescriptorField(description="The address of the endpoint used to communicate synchronization information if required by this endpoint. Must be set to 0", default=0) +) + +ClassSpecificMidiStreamingBulkDataEndpointDescriptorHead = DescriptorFormat( + "bLength" / DescriptorField(description="Size of this descriptor, in bytes: 4+n"), + "bDescriptorType" / DescriptorNumber(AudioClassSpecificDescriptorTypes.CS_ENDPOINT), + "bDescriptorSubtype" / DescriptorField(description="see MidiStreamingEndpointDescriptorSubtypes", default=MidiStreamingEndpointDescriptorSubtypes.MS_GENERAL), + "bNumEmbMIDIJack" / DescriptorField(description="Number of Embedded MIDI Jacks: n", default=1) +) + +ClassSpecificMidiStreamingBulkDataEndpointDescriptorElement = DescriptorFormat( + "baAssocJackID" / construct.Int8ul # ID of the embedded eack that is associated with this endpoint +) \ No newline at end of file diff --git a/usb_protocol/types/descriptors/uac2.py b/usb_protocol/types/descriptors/uac2.py index 341d3c8..2c262f2 100644 --- a/usb_protocol/types/descriptors/uac2.py +++ b/usb_protocol/types/descriptors/uac2.py @@ -5,17 +5,13 @@ NOTE: This is not complete yet and will be extended as needed """ -from build.lib.usb_protocol.emitters import descriptor -import unittest -from enum import IntEnum +from usb_protocol.emitters import descriptor +from enum import IntEnum import construct -from construct import this, Default -from .. import LanguageIDs from ..descriptor import \ - DescriptorField, DescriptorNumber, DescriptorFormat, \ - BCDFieldAdapter, DescriptorLength + DescriptorField, DescriptorNumber, DescriptorFormat from .uac import * @@ -303,4 +299,43 @@ ClassSpecificAudioStreamingIsochronousAudioDataEndpointDescriptor = DescriptorFo "bmControls" / DescriptorField(description="D1..0: pitch control D3..2: data overrun control; D5..4: data underrun control;", default=0), "bLockDelayUnits" / DescriptorField(description="wLockDelay unit: 0: undefined; 1: milliseconds; 2: decoded PCM samples;", default=0), "wLockDelay" / DescriptorField(description="the time it takes this endpoint to reliably lock its internal clock recovery circuitry. Units see bLockDelayUnits", default=0) -) \ No newline at end of file +) + +###################### MIDI ######################### + +class MidiStreamingGroupTerminalBlockDescriptorSubtypes(IntEnum): + GR_TRM_BLOCK_UNDEFINED = 0x00 + GR_TRM_BLOCK_HEADER = 0x01 + GR_TRM_BLOCK = 0x02 + +class GroupTerminalBlockType(IntEnum): + BIDIRECTIONAL = 0x00 + INPUT_ONLY = 0x01 + OUTPUT_ONLY = 0x02 + +class GroupTerminalDefaultMidiProtocol(IntEnum): + USE_MIDI_CI = 0x00 + MIDI_1_0_UP_TO_64_BITS = 0x01 + MIDI_1_0_UP_TO_64_BITS_AND_JRTS = 0x02 + MIDI_1_0_UP_TO_128_BITS = 0x03 + MIDI_1_0_UP_TO_128_BITS_AND_JRTS = 0x04 + MIDI_2_0 = 0x11 + MIDI_2_0_AND_JRTS = 0x12 + +class GroupTerminalNumber(IntEnum): + GROUP_1 = 0x00 + GROUP_2 = 0x01 + GROUP_3 = 0x02 + GROUP_4 = 0x03 + GROUP_5 = 0x04 + GROUP_6 = 0x05 + GROUP_7 = 0x06 + GROUP_8 = 0x07 + GROUP_9 = 0x08 + GROUP_10 = 0x09 + GROUP_11 = 0x0A + GROUP_12 = 0x0B + GROUP_13 = 0x0C + GROUP_14 = 0x0D + GROUP_15 = 0x0E + GROUP_16 = 0x0F \ No newline at end of file