[USBAUDIO]
[reactos.git] / reactos / drivers / usb / usbaudio / filter.c
index 93ad768..d066af0 100644 (file)
@@ -90,13 +90,708 @@ static KSPIN_DISPATCH UsbAudioPinDispatch =
     NULL
 };
 
+NTSTATUS NTAPI FilterAudioVolumeHandler(IN PIRP Irp, IN PKSIDENTIFIER  Request, IN OUT PVOID  Data);
+NTSTATUS NTAPI FilterAudioMuteHandler(IN PIRP Irp, IN PKSIDENTIFIER  Request, IN OUT PVOID  Data);
+
+DEFINE_KSPROPERTY_TABLE_AUDIO_VOLUME(FilterAudioVolumePropertySet, FilterAudioVolumeHandler);
+DEFINE_KSPROPERTY_TABLE_AUDIO_MUTE(FilterAudioMutePropertySet, FilterAudioMuteHandler);
+
+
+static KSPROPERTY_SET FilterAudioVolumePropertySetArray[] =
+{
+    {
+        &KSPROPSETID_Audio,
+        sizeof(FilterAudioVolumePropertySet) / sizeof(KSPROPERTY_ITEM),
+        (const KSPROPERTY_ITEM*)&FilterAudioVolumePropertySet,
+        0,
+        NULL
+    }
+};
+
+static KSPROPERTY_SET FilterAudioMutePropertySetArray[] =
+{
+    {
+        &KSPROPSETID_Audio,
+        sizeof(FilterAudioMutePropertySet) / sizeof(KSPROPERTY_ITEM),
+        (const KSPROPERTY_ITEM*)&FilterAudioMutePropertySet,
+        0,
+        NULL
+    }
+};
 
 NTSTATUS
-BuildUSBAudioFilterTopology(
-    PKSDEVICE Device)
+UsbAudioGetSetProperty(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN UCHAR Request,
+    IN USHORT Value,
+    IN USHORT Index,
+    IN PVOID TransferBuffer,
+    IN ULONG TransferBufferLength,
+    IN ULONG TransferFlags)
+{
+    PURB Urb;
+    NTSTATUS Status;
+
+    /* allocate urb */
+    Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
+    if (!Urb)
+    {
+        /* no memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* format urb */
+    UsbBuildVendorRequest(Urb,
+        URB_FUNCTION_CLASS_INTERFACE,
+        sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
+        TransferFlags,
+        0,
+        Request,
+        Value,
+        Index,
+        TransferBuffer,
+        NULL,
+        TransferBufferLength,
+        NULL);
+
+    /* submit urb */
+    Status = SubmitUrbSync(DeviceObject, Urb);
+
+    DPRINT1("UsbAudioGetSetProperty Status %x\n", Status);
+    FreeFunction(Urb);
+    return Status;
+}
+
+PNODE_CONTEXT
+FindNodeContextWithNode(
+    IN PNODE_CONTEXT NodeContext,
+    IN ULONG NodeContextCount,
+    IN ULONG NodeId)
+{
+    ULONG Index, NodeIndex;
+    for (Index = 0; Index < NodeContextCount; Index++)
+    {
+        for (NodeIndex = 0; NodeIndex < NodeContext[Index].NodeCount; NodeIndex++)
+        {
+            if (NodeContext[Index].Nodes[NodeIndex] == NodeId)
+            {
+                return &NodeContext[Index];
+            }
+        }
+    }
+    return NULL;
+}
+
+
+NTSTATUS
+NTAPI
+FilterAudioMuteHandler(
+    IN PIRP Irp,
+    IN PKSIDENTIFIER  Request,
+    IN OUT PVOID  Data)
+{
+    PKSNODEPROPERTY_AUDIO_CHANNEL Property;
+    PKSFILTER Filter;
+    PFILTER_CONTEXT FilterContext;
+    PNODE_CONTEXT NodeContext;
+    PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR FeatureUnitDescriptor;
+    NTSTATUS Status = STATUS_INVALID_PARAMETER;
+
+    /* get filter from irp */
+    Filter = KsGetFilterFromIrp(Irp);
+
+    if (Filter)
+    {
+        /* get property */
+        Property = (PKSNODEPROPERTY_AUDIO_CHANNEL)Request;
+
+        /* get filter context */
+        FilterContext = (PFILTER_CONTEXT)Filter->Context;
+
+        /* search for node context */
+        NodeContext = FindNodeContextWithNode(FilterContext->DeviceExtension->NodeContext, FilterContext->DeviceExtension->NodeContextCount, Property->NodeProperty.NodeId);
+        if (NodeContext)
+        {
+            FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)NodeContext->Descriptor;
+            if (Property->NodeProperty.Property.Flags & KSPROPERTY_TYPE_GET)
+            {
+                Status = UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x81, 0x100, FeatureUnitDescriptor->bUnitID << 8, Data, 1, USBD_TRANSFER_DIRECTION_IN);
+                Irp->IoStatus.Information = sizeof(BOOL);
+            }
+            else
+            {
+                Status = UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x01, 0x100, FeatureUnitDescriptor->bUnitID << 8, Data, 1, USBD_TRANSFER_DIRECTION_OUT);
+            }
+        }
+    }
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+FilterAudioVolumeHandler(
+    IN PIRP Irp,
+    IN PKSIDENTIFIER  Request,
+    IN OUT PVOID  Data)
 {
     UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
+    return STATUS_SUCCESS;
+}
+
+
+ULONG
+CountTopologyComponents(
+    IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
+    OUT PULONG OutDescriptorCount)
+{
+    PUSB_INTERFACE_DESCRIPTOR Descriptor;
+    PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor;
+    PUSB_COMMON_DESCRIPTOR CommonDescriptor;
+    PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor;
+    PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR FeatureUnitDescriptor;
+    PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR MixerUnitDescriptor;
+    ULONG NodeCount = 0;
+    ULONG DescriptorCount = 0;
+    UCHAR Value;
+
+    for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
+    Descriptor != NULL;
+        Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1))
+    {
+        if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */
+        {
+            InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+            if (InterfaceHeaderDescriptor != NULL)
+            {
+                CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+                while (CommonDescriptor)
+                {
+                    InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor;
+                    if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/ || InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/)
+                    {
+                        NodeCount++;
+                        DescriptorCount++;
+                    }
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x06 /* FEATURE_UNIT*/)
+                    {
+                        FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)InputTerminalDescriptor;
+                        DescriptorCount++;
+                        Value = FeatureUnitDescriptor->bmaControls[0];
+                        if (Value & 0x01) /* MUTE*/
+                            NodeCount++;
+                        if (Value & 0x02) /* VOLUME */
+                            NodeCount++;
+                        if (Value & 0x04) /* BASS */
+                            NodeCount++;
+                        if (Value & 0x08) /* MID */
+                            NodeCount++;
+                        if (Value & 0x10) /* TREBLE */
+                            NodeCount++;
+                        if (Value & 0x20) /* GRAPHIC EQUALIZER */
+                            NodeCount++;
+                        if (Value & 0x40) /* AUTOMATIC GAIN */
+                            NodeCount++;
+                        if (Value & 0x80) /* DELAY */
+                            NodeCount++;
+
+                        /* FIXME handle logical channels too */
+                    }
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x04 /* MIXER_UNIT */)
+                    {
+                        MixerUnitDescriptor = (PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR)InputTerminalDescriptor;
+                        DescriptorCount++;
+                        NodeCount += MixerUnitDescriptor->bNrInPins + 1; /* KSNODETYPE_SUPERMIX for each source pin and KSNODETYPE_SUM for target */
+                    }
+                    else
+                    {
+                        UNIMPLEMENTED
+                    }
+                    CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
+                    if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength))
+                        break;
+                }
+            }
+        }
+    }
+    *OutDescriptorCount = DescriptorCount;
+    return NodeCount;
+}
+
+PNODE_CONTEXT
+FindNodeContextWithId(
+    IN PNODE_CONTEXT NodeContext,
+    IN ULONG NodeContextCount,
+    IN UCHAR TerminalId)
+{
+    ULONG Index;
+    PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor;
+
+    for (Index = 0; Index < NodeContextCount; Index++)
+    {
+        TerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)NodeContext[Index].Descriptor;
+        if (TerminalDescriptor->bTerminalID == TerminalId)
+            return &NodeContext[Index];
+    }
+    return NULL;
+}
+
+NTSTATUS
+BuildUSBAudioFilterTopology(
+    PKSDEVICE Device,
+    PKSFILTER_DESCRIPTOR FilterDescriptor)
+{
+    PDEVICE_EXTENSION DeviceExtension;
+    ULONG NodeCount, Index, DescriptorCount, StreamingTerminalIndex, NonStreamingTerminalDescriptorCount, TotalTerminalDescriptorCount, StreamingTerminalPinOffset, ControlDescriptorCount;
+    UCHAR Value;
+    PUSB_INTERFACE_DESCRIPTOR Descriptor;
+    PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor;
+    PUSB_COMMON_DESCRIPTOR CommonDescriptor;
+    PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor;
+    PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR FeatureUnitDescriptor;
+    PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR MixerUnitDescriptor;
+    PUSB_AUDIO_CONTROL_OUTPUT_TERMINAL_DESCRIPTOR OutputTerminalDescriptor;
+    PKSNODE_DESCRIPTOR NodeDescriptors;
+    PNODE_CONTEXT NodeContext, PreviousNodeContext;
+    PKSTOPOLOGY_CONNECTION Connections;
+    PKSAUTOMATION_TABLE AutomationTable;
+
+    /* get device extension */
+    DeviceExtension = Device->Context;
+
+    /* count topology nodes */
+    NodeCount = CountTopologyComponents(DeviceExtension->ConfigurationDescriptor, &ControlDescriptorCount);
+
+    /* init node descriptors*/
+    FilterDescriptor->NodeDescriptors = NodeDescriptors = AllocFunction(NodeCount * sizeof(KSNODE_DESCRIPTOR));
+    if (FilterDescriptor->NodeDescriptors == NULL)
+    {
+        /* no memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    FilterDescriptor->NodeDescriptorSize = sizeof(KSNODE_DESCRIPTOR);
+
+    DeviceExtension->NodeContext = NodeContext = AllocFunction(sizeof(NODE_CONTEXT) * ControlDescriptorCount);
+    if (!NodeContext)
+    {
+        /* no memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    DeviceExtension->NodeContextCount = ControlDescriptorCount;
+    DescriptorCount = 0;
+
+    /* first enumerate all topology nodes */
+    for (Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
+    Descriptor != NULL;
+        Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1))
+    {
+        if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */
+        {
+            InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+            if (InterfaceHeaderDescriptor != NULL)
+            {
+                CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+                while (CommonDescriptor)
+                {
+                    InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor;
+                    if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/)
+                    {
+                        if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SRC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SRC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Descriptor = CommonDescriptor;
+                            NodeContext[DescriptorCount].NodeCount = 1;
+                            NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount;
+                            DescriptorCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+                        else if ((InputTerminalDescriptor->wTerminalType & 0xFF00) == 0x200)
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_ADC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_ADC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Descriptor = CommonDescriptor;
+                            NodeContext[DescriptorCount].NodeCount = 1;
+                            NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount;
+                            DescriptorCount++;
+
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+                        else if ((InputTerminalDescriptor->wTerminalType & 0xFF00) == 0x300)
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_DAC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_DAC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Descriptor = CommonDescriptor;
+                            NodeContext[DescriptorCount].NodeCount = 1;
+                            NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount;
+                            DescriptorCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+                        else
+                        {
+                            DPRINT1("Unexpected input terminal type %x\n", InputTerminalDescriptor->wTerminalType);
+                        }
+                    }
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/)
+                    {
+                        if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SRC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SRC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Descriptor = CommonDescriptor;
+                            NodeContext[DescriptorCount].NodeCount = 1;
+                            NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount;
+                            DescriptorCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+                        else if ((InputTerminalDescriptor->wTerminalType & 0xFF00) == 0x300)
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_DAC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_DAC;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Descriptor = CommonDescriptor;
+                            NodeContext[DescriptorCount].NodeCount = 1;
+                            NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount;
+                            DescriptorCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+                        else
+                        {
+                            DPRINT1("Unexpected output terminal type %x\n", InputTerminalDescriptor->wTerminalType);
+                        }
+                    }
+
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x06 /* FEATURE_UNIT*/)
+                    {
+                        FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)CommonDescriptor;
+                        Value = FeatureUnitDescriptor->bmaControls[0];
+                        if (Value & 0x01) /* MUTE*/
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_MUTE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_MUTE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+                            if (AutomationTable)
+                            {
+                                AutomationTable->PropertySets = FilterAudioMutePropertySetArray;
+                                AutomationTable->PropertySetsCount = 1;
+                                AutomationTable->PropertyItemSize = sizeof(KSPROPERTY_ITEM);
+                            }
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+                        if (Value & 0x02) /* VOLUME */
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_VOLUME;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_VOLUME;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+                            if (AutomationTable)
+                            {
+                                AutomationTable->PropertySets = FilterAudioVolumePropertySetArray;
+                                AutomationTable->PropertySetsCount = 1;
+                                AutomationTable->PropertyItemSize = sizeof(KSPROPERTY_ITEM);
+                            }
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+
+                        if (Value & 0x04) /* BASS */
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+
+                        if (Value & 0x08) /* MID */
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+
+                        if (Value & 0x10) /* TREBLE */
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+
+                        if (Value & 0x20) /* GRAPHIC EQUALIZER */
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+
+                        if (Value & 0x40) /* AUTOMATIC GAIN */
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+
+                        if (Value & 0x80) /* DELAY */
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+                        NodeContext[DescriptorCount].Descriptor = CommonDescriptor;
+                        DescriptorCount++;
+
+                    }
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x04 /* MIXER_UNIT */)
+                    {
+                        MixerUnitDescriptor = (PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR)CommonDescriptor;
+                        for (Index = 0; Index < MixerUnitDescriptor->bNrInPins; Index++)
+                        {
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SUPERMIX;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SUPERMIX;
+                            NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                            /* insert into node context*/
+                            NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                            NodeContext[DescriptorCount].NodeCount++;
+
+                            FilterDescriptor->NodeDescriptorsCount++;
+                        }
+
+                        NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SUM;
+                        NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SUM;
+                        NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE));
+
+                        /* insert into node context*/
+                        NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount;
+                        NodeContext[DescriptorCount].NodeCount++;
+                        NodeContext[DescriptorCount].Descriptor = CommonDescriptor;
+                        DescriptorCount++;
+
+                        FilterDescriptor->NodeDescriptorsCount++;
+                    }
+                    else
+                    {
+                        UNIMPLEMENTED
+                    }
+                    CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
+                    if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength))
+                        break;
+                }
+            }
+        }
+    }
+
+    /* FIXME determine connections count*/
+    FilterDescriptor->Connections = Connections = AllocFunction(sizeof(KSTOPOLOGY_CONNECTION) * FilterDescriptor->NodeDescriptorsCount * 2);
+    if (!FilterDescriptor->Connections)
+    {
+        /* no memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+    FilterDescriptor->ConnectionsCount = 0;
+
+    /* now build connections array */
+    DescriptorCount = 0;
+    StreamingTerminalIndex = 0;
+    NodeCount = 0;
+
+    CountTerminalUnits(DeviceExtension->ConfigurationDescriptor, &NonStreamingTerminalDescriptorCount, &TotalTerminalDescriptorCount);
+    StreamingTerminalPinOffset = TotalTerminalDescriptorCount - NonStreamingTerminalDescriptorCount;
+
+    for (Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
+    Descriptor != NULL;
+        Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1))
+    {
+        if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */
+        {
+            InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+            if (InterfaceHeaderDescriptor != NULL)
+            {
+                CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE);
+                while (CommonDescriptor)
+                {
+                    InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor;
+                    if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/)
+                    {
+                        if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+                        {
+                             Connections[FilterDescriptor->ConnectionsCount].FromNode = KSFILTER_NODE;
+                             Connections[FilterDescriptor->ConnectionsCount].FromNodePin = StreamingTerminalIndex;
+                             Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1;
+                             Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0];
+                             FilterDescriptor->ConnectionsCount++;
+                             StreamingTerminalIndex++;
+
+                        }
+                        else
+                        {
+                            Connections[FilterDescriptor->ConnectionsCount].FromNode = KSFILTER_NODE;
+                            Connections[FilterDescriptor->ConnectionsCount].FromNodePin = StreamingTerminalPinOffset;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0];
+                            FilterDescriptor->ConnectionsCount++;
+                            StreamingTerminalPinOffset++;
+                        }
+                        DescriptorCount++;
+                    }
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/)
+                    {
+                        OutputTerminalDescriptor = (PUSB_AUDIO_CONTROL_OUTPUT_TERMINAL_DESCRIPTOR)CommonDescriptor;
+                        PreviousNodeContext = FindNodeContextWithId(NodeContext, ControlDescriptorCount, OutputTerminalDescriptor->bSourceID);
+                        if (PreviousNodeContext)
+                        {
+                            Connections[FilterDescriptor->ConnectionsCount].FromNode = PreviousNodeContext->Nodes[PreviousNodeContext->NodeCount - 1];
+                            Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0];
+                            FilterDescriptor->ConnectionsCount++;
+                        }
+
+                        if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE)
+                        {
+                            Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[0];
+                            Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNodePin = StreamingTerminalIndex;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNode = KSFILTER_NODE;
+                            FilterDescriptor->ConnectionsCount++;
+                            StreamingTerminalIndex++;
+                        }
+                        else
+                        {
+                            Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[0];
+                            Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNodePin = StreamingTerminalPinOffset;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNode = KSFILTER_NODE;
+                            FilterDescriptor->ConnectionsCount++;
+
+                            StreamingTerminalPinOffset++;
+                        }
+                        DescriptorCount++;
+                    }
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x06 /* FEATURE_UNIT*/)
+                    {
+                        FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)InputTerminalDescriptor;
+                        PreviousNodeContext = FindNodeContextWithId(NodeContext, ControlDescriptorCount, FeatureUnitDescriptor->bSourceID);
+                        if (PreviousNodeContext)
+                        {
+                            Connections[FilterDescriptor->ConnectionsCount].FromNode = PreviousNodeContext->Nodes[PreviousNodeContext->NodeCount-1];
+                            Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0];
+                            FilterDescriptor->ConnectionsCount++;
+                        }
+                        for (Index = 1; Index < NodeContext[DescriptorCount].NodeCount; Index++)
+                        {
+                            Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[Index - 1];
+                            Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[Index];
+                            FilterDescriptor->ConnectionsCount++;
+                        }
+
+                        DescriptorCount++;
+                    }
+                    else if (InputTerminalDescriptor->bDescriptorSubtype == 0x04 /* MIXER_UNIT */)
+                    {
+                        MixerUnitDescriptor = (PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR)InputTerminalDescriptor;
+                        for (Index = 0; Index < MixerUnitDescriptor->bNrInPins; Index++)
+                        {
+                            Value = MixerUnitDescriptor->baSourceID[Index];
+                            PreviousNodeContext = FindNodeContextWithId(NodeContext, ControlDescriptorCount, Value);
+                            if (PreviousNodeContext)
+                            {
+                                Connections[FilterDescriptor->ConnectionsCount].FromNode = PreviousNodeContext->Nodes[PreviousNodeContext->NodeCount - 1];
+                                Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0;
+                                Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1;
+                                Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[Index];
+                                FilterDescriptor->ConnectionsCount++;
+                            }
+
+                            Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[Index];
+                            Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1 + Index;
+                            Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount-1];
+                            FilterDescriptor->ConnectionsCount++;
+                        }
+                        DescriptorCount++;
+                    }
+                    else
+                    {
+                        UNIMPLEMENTED
+                    }
+                    CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
+                    if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength))
+                        break;
+                }
+            }
+        }
+    }
+
+
+
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -143,6 +838,7 @@ USBAudioFilterCreate(
 
 
 VOID
+NTAPI
 CountTerminalUnits(
     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
     OUT PULONG NonStreamingTerminalDescriptorCount,
@@ -411,7 +1107,7 @@ USBAudioPinBuildDescriptors(
     DeviceExtension = Device->Context;
 
     CountTerminalUnits(DeviceExtension->ConfigurationDescriptor, &NonStreamingTerminalDescriptorCount, &TotalTerminalDescriptorCount);
-    DPRINT1("TotalTerminalDescriptorCount %lu NonStreamingTerminalDescriptorCount %lu", TotalTerminalDescriptorCount, NonStreamingTerminalDescriptorCount);
+    DPRINT("TotalTerminalDescriptorCount %lu NonStreamingTerminalDescriptorCount %lu\n", TotalTerminalDescriptorCount, NonStreamingTerminalDescriptorCount);
 
     /* allocate pins */
     Pins = AllocFunction(sizeof(KSPIN_DESCRIPTOR_EX) * TotalTerminalDescriptorCount);
@@ -448,7 +1144,10 @@ USBAudioPinBuildDescriptors(
                 Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN;
             }
 
+            /* data intersect handler */
+            Pins[Index].IntersectHandler = UsbAudioPinDataIntersect;
 
+            /* pin flags */
             Pins[Index].Flags = KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY | KSFILTER_FLAG_CRITICAL_PROCESSING;
 
             /* irp sinks / sources can be instantiated */
@@ -487,22 +1186,176 @@ USBAudioPinBuildDescriptors(
     return STATUS_SUCCESS;
 }
 
+NTSTATUS
+NTAPI
+USBAudioGetDescriptor(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN UCHAR DescriptorType,
+    IN ULONG DescriptorLength,
+    IN UCHAR DescriptorIndex,
+    IN LANGID LanguageId,
+    OUT PVOID *OutDescriptor)
+{
+    PURB Urb;
+    NTSTATUS Status;
+    PVOID Descriptor;
+
+    /* sanity checks */
+    ASSERT(DeviceObject);
+    ASSERT(OutDescriptor);
+    ASSERT(DescriptorLength);
+
+    //
+    // first allocate descriptor buffer
+    //
+    Descriptor = AllocFunction(DescriptorLength);
+    if (!Descriptor)
+    {
+        /* no memory */
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* allocate urb */
+    Urb = (PURB)AllocFunction(sizeof(URB));
+    if (!Urb)
+    {
+        /* no memory */
+        FreeFunction(Descriptor);
+        return STATUS_INSUFFICIENT_RESOURCES;
+    }
+
+    /* initialize urb */
+    UsbBuildGetDescriptorRequest(Urb,
+        sizeof(Urb->UrbControlDescriptorRequest),
+        DescriptorType,
+        DescriptorIndex,
+        LanguageId,
+        Descriptor,
+        NULL,
+        DescriptorLength,
+        NULL);
+
+    /* submit urb */
+    Status = SubmitUrbSync(DeviceObject, Urb);
+
+    /* free urb */
+    FreeFunction(Urb);
+
+    if (NT_SUCCESS(Status))
+    {
+        /* store result */
+        *OutDescriptor = Descriptor;
+    }
+    else
+    {
+        /* failed */
+        FreeFunction(Descriptor);
+    }
+
+    /* done */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+USBAudioGetStringDescriptor(
+    IN PDEVICE_OBJECT DeviceObject,
+    IN ULONG DescriptorLength,
+    IN UCHAR DescriptorIndex,
+    IN LANGID LanguageId,
+    OUT PVOID *OutDescriptor)
+{
+    NTSTATUS Status;
+
+    /* retrieve descriptor */
+    Status = USBAudioGetDescriptor(DeviceObject, USB_STRING_DESCRIPTOR_TYPE, DescriptorLength, DescriptorIndex, LanguageId, OutDescriptor);
+    if (!NT_SUCCESS(Status))
+    {
+        // failed
+        return Status;
+    }
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+USBAudioRegCreateMediaCategoriesKey(
+    IN PUNICODE_STRING Name, 
+    OUT PHANDLE OutHandle)
+{
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING DestinationString;
+    HANDLE Handle;
+
+    /* initialize root name*/
+    RtlInitUnicodeString(&DestinationString, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\");
+
+    /* initialize object attributes */
+    InitializeObjectAttributes(&ObjectAttributes, &DestinationString, OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE, NULL, NULL);
+
+    /* create the key */
+    Status = ZwOpenKey(&Handle, KEY_ALL_ACCESS, &ObjectAttributes);
+    if (NT_SUCCESS(Status))
+    {
+        /* initialize object attributes */
+        InitializeObjectAttributes(&ObjectAttributes, Name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, Handle, NULL);
+
+        Status = ZwCreateKey(OutHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, 0, NULL);
+        ZwClose(Handle);
+
+    }
+    return Status;
+}
+
+
 NTSTATUS
 USBAudioInitComponentId(
     PKSDEVICE Device,
     IN PKSCOMPONENTID ComponentId)
 {
     PDEVICE_EXTENSION DeviceExtension;
+    NTSTATUS Status;
+    LPWSTR DescriptionBuffer;
+    UNICODE_STRING GuidString;
+    UNICODE_STRING Name;
+    HANDLE hKey;
+    GUID TempGuid;
 
     /* get device extension */
     DeviceExtension = Device->Context;
 
+    /* init component id */
+    ComponentId->Component = KSCOMPONENTID_USBAUDIO;
+    ComponentId->Version = HIBYTE(DeviceExtension->DeviceDescriptor->bcdDevice);
+    ComponentId->Revision = LOBYTE(DeviceExtension->DeviceDescriptor->bcdDevice);
+
     INIT_USBAUDIO_MID(&ComponentId->Manufacturer, DeviceExtension->DeviceDescriptor->idVendor);
     INIT_USBAUDIO_PID(&ComponentId->Product, DeviceExtension->DeviceDescriptor->idProduct);
+    INIT_USBAUDIO_PRODUCT_NAME(&TempGuid, DeviceExtension->DeviceDescriptor->idVendor, DeviceExtension->DeviceDescriptor->idProduct, 0);
 
-    //ComponentId->Component = KSCOMPONENTID_USBAUDIO;
-    UNIMPLEMENTED
-    return STATUS_NOT_IMPLEMENTED;
+    if (DeviceExtension->DeviceDescriptor->iProduct)
+    {
+        Status = USBAudioGetStringDescriptor(DeviceExtension->LowerDevice, 100 * sizeof(WCHAR), DeviceExtension->DeviceDescriptor->iProduct, 0x0409 /* FIXME */, (PVOID*)&DescriptionBuffer);
+        if (NT_SUCCESS(Status))
+        {
+            Status = RtlStringFromGUID(&TempGuid, &GuidString);
+            if (NT_SUCCESS(Status))
+            {
+                Status = USBAudioRegCreateMediaCategoriesKey(&GuidString, &hKey);
+                if (NT_SUCCESS(Status))
+                {
+                    RtlInitUnicodeString(&Name, L"Name");
+                    ZwSetValueKey(hKey, &Name, 0, REG_SZ, DescriptionBuffer, (wcslen(DescriptionBuffer) + 1) * sizeof(WCHAR));
+                    ZwClose(hKey);
+
+                    INIT_USBAUDIO_PRODUCT_NAME(&ComponentId->Name, DeviceExtension->DeviceDescriptor->idVendor, DeviceExtension->DeviceDescriptor->idProduct, 0);
+                }
+                RtlFreeUnicodeString(&GuidString);
+            }
+            FreeFunction(DescriptionBuffer);
+        }
+    }
+    return STATUS_SUCCESS;
 }
 
 
@@ -542,8 +1395,8 @@ USBAudioCreateFilterContext(
     if (!NT_SUCCESS(Status))
     {
         /* failed*/
-        //FreeFunction(ComponentId);
-        //return Status;
+        FreeFunction(ComponentId);
+        return Status;
     }
     FilterDescriptor->ComponentId = ComponentId;
 
@@ -557,17 +1410,17 @@ USBAudioCreateFilterContext(
     }
 
     /* build topology */
-    Status = BuildUSBAudioFilterTopology(Device);
+    Status = BuildUSBAudioFilterTopology(Device, FilterDescriptor);
     if (!NT_SUCCESS(Status))
     {
         /* failed*/
-        //FreeFunction(ComponentId);
-        //return Status;
+        FreeFunction(ComponentId);
+        return Status;
     }
 
     /* lets create the filter */
     Status = KsCreateFilterFactory(Device->FunctionalDeviceObject, FilterDescriptor, ReferenceString, NULL, KSCREATE_ITEM_FREEONSTOP, NULL, NULL, NULL);
-    DPRINT1("KsCreateFilterFactory: %x\n", Status);
+    DPRINT("KsCreateFilterFactory: %x\n", Status);
 
     return Status;
 }