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