Jack Description Property
In Windows Vista and later, the KSPROPERTY_JACK_DESCRIPTION property describes an audio jack or other physical connector on an audio adapter. The property value describes the color of the jack, the physical location of the jack, the connector type, and other jack features. The purpose of this information is to help the user to find the correct jack for plugging in an audio endpoint device such as a microphone, headphones, or speakers. For more information, see Audio Endpoint Devices.
If a KS filter on an audio adapter supports the KSPROPERTY_JACK_DESCRIPTION property, the Windows multimedia control panel, Mmsys.cpl, displays the jack information for the bridge pins on the filter. A bridge pin represents a connection (typically, a jack) to an audio endpoint device. Although the property value contains information about a pin (or rather, the jack or jacks that are associated with the pin), the property is a property of the filter, not of the pin. For more information about bridge pins, see Audio Filter Graphs. For more information about filter properties and pin properties, see Filter, Pin, and Node Properties.
An audio application can obtain the KSPROPERTY_JACK_DESCRIPTION property value for an audio endpoint device by calling the IKsJackDescription::GetJackDescription method in the DeviceTopology API. For example, an application can use the jack information to help the user to distinguish a microphone plugged into a green XLR jack from a microphone plugged into an orange XLR jack. For more information about the DeviceTopology API, see Device Topologies.
The Microsoft HD Audio class driver automatically constructs the KSPROPERTY_JACK_DESCRIPTION property values from the data that it reads from the pin-configuration registers in an HD Audio codec. However, any KS-based audio driver can implement support for this property in its filter automation tables. For more information about the HD Audio class driver, see HD Audio and UAA. For more information about pin-configuration registers, see the Pin Configuration Guidelines for High Definition Audio Devices white paper.
An audio endpoint device can connect to a bridge pin through one or more jacks. For example, a set of (two-channel) stereo speakers requires one jack, but a set of 5.1 surround-sound speakers requires three jacks (assuming that each jack handles two of the six channels).
The description for each jack is contained in a KSJACK_DESCRIPTION structure. For example, the KSPROPERTY_JACK_DESCRIPTION property value for an audio endpoint device with one jack contains one KSJACK_DESCRIPTION structure, but the property value for an endpoint device with three jacks contains three KSJACK_DESCRIPTION structures. In either case, the KSJACK_DESCRIPTION structure or structures in the property value are preceded by a KSMULTIPLE_ITEM structure that specifies the size of the property value. For more information, see KSPROPERTY_JACK_DESCRIPTION.
Jack information is particularly useful for helping users to distinguish among the jacks that connect to a multichannel speaker configuration. The following code example shows an array of KSJACK_DESCRIPTION structures that an audio driver uses to describe the three jacks for a set of 5.1 surround speakers:
KSJACK_DESCRIPTION ar_5dot1_Jacks[] =
{
// Jack 1
{
(SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT), // ChannelMapping (L,R)
RGB(0,255,0), // Color (green)
eConnType3Point5mm, // ConnectionType
eGeoLocRear, // GeoLocation
eGenLocPrimaryBox, // GenLocation
ePortConnJack, // PortConnection
TRUE // IsConnected
},
// Jack 2
{
(SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY), // (C,Sub)
RGB(0,0,255), // (red)
eConnType3Point5mm,
eGeoLocRear,
eGenLocPrimaryBox,
ePortConnJack,
TRUE
},
// Jack 3
{
(SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT), // (SL,SR)
RGB(0,255,255), // (yellow)
eConnType3Point5mm,
eGeoLocRear,
eGenLocPrimaryBox,
ePortConnJack,
TRUE
}
};
If the audio hardware can detect whether the device is plugged in, the driver dynamically updates the value of this member to indicate whether the device is currently plugged in (TRUE) or unplugged (FALSE)
In the preceding code example, the IsConnected member in each array element is set to TRUE to indicate that the endpoint device is plugged into the jack. However, if the hardware lacks jack presence detection, IsConnected must always be set to TRUE, whether there is a device plugged into the jack. To remove the ambiguity that results from this dual meaning of the TRUE return value, a client application can call IKsJackDescription2::GetJackDescription2 to read the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint does in fact support jack presence detection. In that case, the value of the IsConnected member can be interpreted as an accurate reflection of the insertion status of the jack.
The RGB macro that appears in the preceding structures is defined in header file Wingdi.h in the Windows SDK.
In addition, an array of jack descriptions can be used to show that two or more jacks are functionally equivalent to each other. In the following code example, the audio driver combines the jack descriptions for a yellow RCA jack and for a black digital-optical jack into one array to indicate to the user that the two jacks carry the same signal:
KSJACK_DESCRIPTION ar_SPDIF_Jacks[] =
{
// Jack 1
{
(SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT), // ChannelMapping (L,R)
RGB(0,255,255), // Color (yellow)
eConnTypeRCA, // ConnectionType (RCA)
eGeoLocRear, // GeoLocation
eGenLocPrimaryBox, // GenLocation
ePortConnJack, // PortConnection
TRUE // IsConnected
},
// Jack 2
{
(SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT), // (L,R)
RGB(0,0,0), // (black)
eConnTypeOptical, // (optical)
eGeoLocRear,
eGenLocPrimaryBox,
ePortConnJack,
TRUE
}
};
In the preceding code example, the values of the ChannelMapping members in the two KSJACK_DESCRIPTION structures are identical.
The "Simple" MSVAD sample driver in the WDK (in sample directory Src\Audio\Msvad\Simple) can be adapted to support the KSPROPERTY_JACK_DESCRIPTION property. This sample driver is convenient for demonstrating the use of the property because it does not require actual hardware. Thus, it can be installed on any computer running Windows. (However, only Windows Vista and later operating systems provide full support for the KSPROPERTY_JACK_DESCRIPTION property.) For more information about this sample, see Windows Driver Kit Samples.
The topology filter for the Simple MSVAD sample defines three bridge pins. These pins are listed in the following table.
Pin ID | Description |
---|---|
KSPIN_TOPO_SYNTHIN_SOURCE |
MIDI input jack |
KSPIN_TOPO_MIC_SOURCE |
Microphone input jack |
KSPIN_TOPO_LINEOUT_DEST |
Stereo speaker output jack |
The remainder of this topic explains how to modify the Simple MSVAD sample driver to provide the jack information for the three bridge pins.
First, the jack information for these pins can be specified as follows:
// Describe MIDI input jack (pin ID = KSPIN_TOPO_SYNTHIN_SOURCE).
static KSJACK_DESCRIPTION SynthIn_Jack[] =
{
{
0, // ChannelMapping
RGB(255,255,0), // Color (cyan)
eConnType3Point5mm, // ConnectionType
eGeoLocRear, // GeoLocation
eGenLocPrimaryBox, // GenLocation
ePortConnJack, // PortConnection
TRUE // IsConnected
}
};
// Describe microphone jack (pin ID = KSPIN_TOPO_MIC_SOURCE).
static KSJACK_DESCRIPTION MicIn_Jack[] =
{
{
0,
RGB(0,128,255), // (orange)
eConnType3Point5mm,
eGeoLocFront,
eGenLocPrimaryBox,
ePortConnJack,
TRUE
}
};
// Describe stereo speaker jack (pin ID = KSPIN_TOPO_LINEOUT_DEST).
static KSJACK_DESCRIPTION LineOut_Jack[] =
{
{
(SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT), // ChannelMapping (L,R)
RGB(0,255,0), // (green)
eConnType3Point5mm,
eGeoLocRear,
eGenLocPrimaryBox,
ePortConnJack,
TRUE
}
};
The preceding code example sets the ChannelMapping members for the two capture pins to 0. Only analog rendering pins should have nonzero ChannelMapping values.
The primary modification to the Simple MSVAD sample is to add the following property handler to the implementation of the topology miniport in sample file Mintopo.cpp:
#define ARRAY_LEN(a) sizeof(a)/sizeof(a[0]);
#define MAXIMUM_VALID_PIN_ID KSPIN_TOPO_WAVEIN_DEST
NTSTATUS
CMiniportTopology::PropertyHandlerJackDescription(
IN PPCPROPERTY_REQUEST PropertyRequest)
{
PAGED_CODE();
ASSERT(PropertyRequest);
DPF_ENTER(("[PropertyHandlerJackDescription]"));
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
ULONG nPinId = (ULONG)-1;
if (PropertyRequest->InstanceSize >= sizeof(ULONG))
{
nPinId = *((PULONG)(PropertyRequest->Instance));
if (nPinId > MAXIMUM_VALID_PIN_ID)
{
ntStatus = STATUS_INVALID_PARAMETER;
}
else if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
{
ntStatus = PropertyHandler_BasicSupport(
PropertyRequest,
KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
VT_ILLEGAL);
}
else
{
PKSJACK_DESCRIPTION pJack = NULL;
ULONG cJacks = 0;
switch (nPinId)
{
case KSPIN_TOPO_SYNTHIN_SOURCE:
pJack = SynthIn_Jack;
cJacks = ARRAY_LEN(SynthIn_Jack);
break;
case KSPIN_TOPO_MIC_SOURCE:
pJack = MicIn_Jack;
cJacks = ARRAY_LEN(MicIn_Jack);
break;
case KSPIN_TOPO_LINEOUT_DEST:
pJack = LineOut_Jack;
cJacks = ARRAY_LEN(LineOut_Jack);
break;
default:
break;
}
ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) +
sizeof(KSJACK_DESCRIPTION) * cJacks;
if (PropertyRequest->ValueSize == 0)
{
PropertyRequest->ValueSize = cbNeeded;
ntStatus = STATUS_BUFFER_OVERFLOW;
}
else if (PropertyRequest->ValueSize < cbNeeded)
{
ntStatus = STATUS_BUFFER_TOO_SMALL;
}
else if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
{
PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
pMI->Size = cbNeeded;
pMI->Count = cJacks;
// Copy jack description structure into Value buffer.
// RtlCopyMemory correctly handles the case Length=0.
PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI + 1);
RtlCopyMemory(pDesc, pJack, pMI->Size * pMI->Count);
ntStatus = STATUS_SUCCESS;
}
}
}
return ntStatus;
}
NTSTATUS
PropertyHandler_TopoFilter(IN PPCPROPERTY_REQUEST PropertyRequest)
{
PAGED_CODE();
ASSERT(PropertyRequest);
DPF_ENTER(("[PropertyHandler_TopoFilter]"));
// PropertyRequest structure is filled by PortCls.
// MajorTarget is a pointer to miniport object for miniports.
//
NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
PCMiniportTopology pMiniport = (PCMiniportTopology)PropertyRequest->MajorTarget;
if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack) &&
(PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION))
{
ntStatus = pMiniport->PropertyHandlerJackDescription(PropertyRequest);
}
return ntStatus;
}
The preceding code example refers to the three KSJACK_DESCRIPTION variables - SynthIn_Jack, MicIn_Jack, and LineOut_Jack - that were defined previously. If the client queries the filter for the jack description of a valid pin, but one that is not a bridge pin (and therefore has no jack description), the query succeeds (with status code STATUS_SUCCESS), but the property handler returns an empty jack description consisting of a KSMULTIPLE_ITEM structure and nothing else. If the client specifies an invalid pin ID (that identifies a nonexistent pin), the handler returns status code STATUS_INVALID_PARAMETER.
Two additional modifications to the Simple MSVAD sample are required to support the KSPROPERTY_JACK_DESCRIPTION property. These are:
Add the declaration of the PropertyHandlerJackDescription method in the preceding code example to the CMiniportTopology class definition in header file Mintopo.h.
Implement an automation table for the topology filter and load the address of this table into the AutomationTable member of the PCFILTER_DESCRIPTOR structure in header file Toptable.h. This structure is named MiniportFilterDescriptor.
To implement the automation table for the filter, insert the following code into header file Toptable.h (before the definition of MiniportFilterDescriptor):
static PCPROPERTY_ITEM PropertiesTopoFilter[] =
{
{
&KSPROPSETID_Jack,
KSPROPERTY_JACK_DESCRIPTION,
KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_BASICSUPPORT,
PropertyHandler_TopoFilter
}
};
DEFINE_PCAUTOMATION_TABLE_PROP(AutomationTopoFilter, PropertiesTopoFilter);
In the preceding code example, the Handler member of the PCPROPERTY_ITEM structure contains a function pointer to the property handler that was added to Mintopo.cpp in a previous step. To make the property handler accessible from the header file, insert an extern function declaration for PropertyHandler_TopoFilter at the start of the header file.
For more information about the jack description property, see Jack Descriptions for Dynamic Audio Subdevices.