Browse Source

Merge pull request #22 from twam/uac2-fixes

Uac2 fixes
main
Mike Walters 3 years ago
committed by GitHub
parent
commit
a9830731a8
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 10 deletions
  1. +1
    -0
      usb_protocol/emitters/descriptors/uac2.py
  2. +70
    -10
      usb_protocol/types/descriptors/uac2.py

+ 1
- 0
usb_protocol/emitters/descriptors/uac2.py View File

@@ -24,6 +24,7 @@ class ClassSpecificAudioControlInterfaceDescriptorEmitter(ComplexDescriptorEmitt
ClockSourceDescriptorEmitter = emitter_for_format(ClockSourceDescriptor)
InputTerminalDescriptorEmitter = emitter_for_format(InputTerminalDescriptor)
OutputTerminalDescriptorEmitter = emitter_for_format(OutputTerminalDescriptor)
FeatureUnitDescriptorEmitter = emitter_for_format(FeatureUnitDescriptor)
AudioStreamingInterfaceDescriptorEmitter = emitter_for_format(AudioStreamingInterfaceDescriptor)
ClassSpecificAudioStreamingInterfaceDescriptorEmitter = emitter_for_format(ClassSpecificAudioStreamingInterfaceDescriptor)
TypeIFormatTypeDescriptorEmitter = emitter_for_format(TypeIFormatTypeDescriptor)


+ 70
- 10
usb_protocol/types/descriptors/uac2.py View File

@@ -633,9 +633,9 @@ InputTerminalDescriptor = DescriptorFormat(
"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, length=4),
"bmControls" / DescriptorField(description="OR combination of ClockFrequencyControl, CopyProtectControl, ConnectorControl, ClusterControl, UnderflowControl and OverflowControl", default=0, length=2),
"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)
"bmControls" / DescriptorField(description="OR combination of CopyProtectControl, ConnectorControl, OverloadControl, ClusterControl, UnderflowControl and OverflowControl", default=0, length=2),
"iTerminal" / DescriptorField(description="ID of the input terminal string descriptor", default=0)
)

OutputTerminalDescriptor = DescriptorFormat(
@@ -648,7 +648,19 @@ OutputTerminalDescriptor = DescriptorFormat(
"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, length=2),
"iTerminal" / DescriptorField(description="ID of the input terminal string description", default=0)
"iTerminal" / DescriptorField(description="ID of the input terminal string descriptor", default=0)
)

FeatureUnitDescriptorLength = construct.Rebuild(construct.Int8ul, construct.len_(construct.this.bmaControls) * 4 + 6)

FeatureUnitDescriptor = DescriptorFormat(
"bLength" / FeatureUnitDescriptorLength,
"bDescriptorType" / DescriptorNumber(AudioClassSpecificStandardDescriptorNumbers.CS_INTERFACE),
"bDescriptorSubtype" / DescriptorNumber(AudioClassSpecificACInterfaceDescriptorSubtypes.FEATURE_UNIT),
"bUnitID" / DescriptorField(description="unique identifier for the unit within the audio function."),
"bSourceID" / DescriptorField(description="ID of the unit or terminal which is connected to this terminal"),
"bmaControls" / construct.Array((construct.this.bLength - 6)//4, construct.Int32ul) * "The control bitmap for all channels",
"iFeature" / DescriptorField(description="ID of the feature unit string descriptor", default=0)
)

AudioStreamingInterfaceDescriptor = DescriptorFormat(
@@ -884,7 +896,7 @@ class UAC2Cases(unittest.TestCase):
parsed = ClockSourceDescriptor.parse([
0x08, # Length
0x24, # Type
0x0B, # Subtype
0x0A, # Subtype
0x01, # Clock ID
0x01, # Attributes
0x01, # Controls
@@ -916,7 +928,7 @@ class UAC2Cases(unittest.TestCase):
self.assertEqual(data, bytes([
0x08, # Length
0x24, # Type
0x0B, # Subtype
0x0A, # Subtype
0x01, # Clock ID
0x01, # Attributes
0x01, # Controls
@@ -936,8 +948,8 @@ class UAC2Cases(unittest.TestCase):
0x01, # Clock ID
0x02, # Number of channels
0x03, 0x00, 0x00, 0x00, # Channel configuration
0x00, # First channel name
0x00, 0x00, # Controls
0x23, # First channel name
0x05, 0x00, # Controls
0x42 # Terminal name
])

@@ -951,7 +963,8 @@ class UAC2Cases(unittest.TestCase):
self.assertEqual(parsed.bCSourceID, 0x01)
self.assertEqual(parsed.bNrChannels, 0x02)
self.assertEqual(parsed.bmChannelConfig, 0x0003)
self.assertEqual(parsed.iChannelNames, 0x00)
self.assertEqual(parsed.iChannelNames, 0x23)
self.assertEqual(parsed.bmControls, 5)
self.assertEqual(parsed.iTerminal, 0x42)

def test_build_input_terminal_descriptor(self):
@@ -962,6 +975,8 @@ class UAC2Cases(unittest.TestCase):
'bCSourceID': 1,
'bNrChannels': 2,
'bmChannelConfig': 3,
'iChannelNames': 0x23,
'bmControls': 5,
'iTerminal': 0x42,
})

@@ -976,8 +991,8 @@ class UAC2Cases(unittest.TestCase):
0x01, # Clock ID
0x02, # Number of channels
0x03, 0x00, 0x00, 0x00, # Channel configuration
0x00, # First channel name
0x00, 0x00, # Controls
0x23, # First channel name
0x05, 0x00, # Controls
0x42 # Terminal name
]))

@@ -1032,6 +1047,51 @@ class UAC2Cases(unittest.TestCase):
0x42 # Terminal name
]))

def test_parse_feature_unit_descriptor(self):
# Parse the relevant descriptor ...
parsed = FeatureUnitDescriptor.parse([
0x12, # Length
0x24, # Type
0x06, # Subtype
0x06, # Unit ID
0x09, # Source ID
0x01, 0x00, 0x00, 0x00, # Controls 0
0x02, 0x00, 0x00, 0x00, # Controls 1
0x03, 0x00, 0x00, 0x00, # Controls 2
0x42 # Unit name
])

# ... and check the descriptor's fields.
self.assertEqual(parsed.bLength, 18)
self.assertEqual(parsed.bDescriptorType, AudioClassSpecificStandardDescriptorNumbers.CS_INTERFACE)
self.assertEqual(parsed.bDescriptorSubtype, AudioClassSpecificACInterfaceDescriptorSubtypes.FEATURE_UNIT)
self.assertEqual(parsed.bUnitID, 0x06)
self.assertEqual(parsed.bSourceID, 0x09)
self.assertEqual(parsed.bmaControls, [0x0001, 0x0002, 0x0003])
self.assertEqual(parsed.iFeature, 0x42)

def test_build_feature_unit_descriptor(self):
# Build the relevant descriptor
data = FeatureUnitDescriptor.build({
'bUnitID': 6,
'bSourceID': 9,
'bmaControls': [1, 2, 3],
'iFeature': 0x42,
})

# ... and check the binary output
self.assertEqual(data, bytes([
0x12, # Length
0x24, # Type
0x06, # Subtype
0x06, # Unit ID
0x09, # Source ID
0x01, 0x00, 0x00, 0x00, # Controls 0
0x02, 0x00, 0x00, 0x00, # Controls 1
0x03, 0x00, 0x00, 0x00, # Controls 2
0x42 # Unit name
]))

def test_parse_audio_streaming_interface_descriptor(self):
# Parse the relevant descriptor ...
parsed = AudioStreamingInterfaceDescriptor.parse([


Loading…
Cancel
Save