|
|
@@ -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([ |
|
|
|