How to gather (but not read) logs for Microsoft’s USB Audio 1.0 class driver

I’ve blogged before about how to gather and read logs for Microsoft’s USB Audio 2.0 class driver usbaudio2.sys. But what about USB Audio 1.0?

Microsoft’s USB Audio 1.0 class driver usbaudio.sys also has logs you can gather. You can’t read them, but you can send them to Microsoft, and then we can read them, because we have the necessary symbols to decode them.

  1. Download usb-audio.wprp (right-click the link and Save.) This actually grabs both USB Audio 1.0 and USB Audio 2.0 logs.
  2. Open an elevated Command Prompt or PowerShell window.
  3. wpr.exe -start usb-audio.wprp
  4. Repro the scenario (e.g. plug in the USB Audio 1.0 device)
  5. wpr.exe -stop some-filename.etl
  6. Send us some-filename.etl

Collecting audio logs the REALLY old-fashioned way – on Windows 7

I’ve blogged before about how to collect audio logs using Windows Performance Recorder profiles (WPRP files), among other things:

I’ve blogged before about what to do if you have an audio problem on Windows 7:

I’ve blogged before about the Trusted Audio Drivers audio digital rights management feature:

Recently I was involved in a Windows 7 audio support issue that involved SHA-1 deprecation and Trusted Audio Drivers. It was very handy to be able to collect audio logs and Code Integrity logs on Windows 7, but it turns out the Windows 7 version of Windows Performance Recorder has slightly different syntax requirements for WPRP files.

Here are the WPRP files we used:

How can my Bluetooth audio device tell Windows what kind of device it is?

I previously blogged about how an audio device driver can tell Windows what kind of audio device it is. But how does the driver know? It depends on the driver.

In Bluetooth-speak, the kind of device is the “class of device.” This is defined in the Bluetooth Assigned Numbers for Baseband.

(As an aside: Microsoft has a Bluetooth Inquiry Record Verifier tool [sdpverify.exe] which ships as part of the Windows Driver Kit. The good news is this lets you inspect the SDP record; the bad news is that the minor class of device is not part of the SDP record.)

If you pair the device, you can look in Device Manager for the “Bluetooth class of device” property. Here’s a screenshot showing the class of device for the E7 headset paired with my Windows system:

The class of device for my E7 Stereo headset is 0x00240404

To parse the hexadecimal value 0x00240404, truncate it to 24 bits and rewrite it in binary first: 0010 0100 0000 0100 0000 0100. Then number the bits as follows: (bit 23) (bit 22) (bit 21) … (bit 3) (bit 2) (bit 1) (bit 0)

The eleven bits 23 through 13 inclusive are the “major service class.” This is set to
001 0010 0000. In particular, bits 21 and 18 are set. Bit 21 is defined as “Audio” and bit 18 is defined as “Rendering”.

The five bits 12 through 8 inclusive are the “major device class.” This is set to 0 0100 which is defined as “Audio/Video”.

The six bits 7 through 2 inclusive are the “minor device class.” This is set to 00 0001. For the major device class “Audio/Video”, this is defined as Wearable Headset Device, which is the kind of audio device this is.

(The final two bits 1 through 0 inclusive are undefined.)

The Bluetooth A2DP profile driver btha2dp.sys translates the “Wearable Headset Device” minor class of device to a KSPIN_DESCRIPTOR.Category value of KSNODETYPE_HEADPHONES.

The Bluetooth Hands-Free profile driver bthhfenum.sys translates “Wearable Headset Device” to KSNODETYPE_HEADSET.

How can my Intel High Definition Audio device tell the audio driver what kind of device it is?

I previously blogged about how an audio device driver can tell Windows what kind of audio device it is. But how does the driver know? It depends on the driver.

Many built-in sound cards and graphics cards follow the Intel High Definition Audio Specification 1.0a (PDF). (Note that “Intel High Definition Audio” is the name of the specification – the audio device does not need to be made by Intel, it just needs to follow the spec Intel published.)

In Intel High Definition Audio-speak, the “kind of device” is called a “Default Device.” It is defined in section 7.3.3.31 Configuration Default.

This is a 32-bit register which is written by sound card manufacturer or the OEM as part of the BIOS or UEFI definition. The bits are numbered bit 31 through bit 0. The four bits 23 through 20 inclusive are used for “Default Device”. To quote the spec:

Default Device indicates the intended use of the jack or device. This can indicate either the label on the jack or the device that is hardwired to the port, as with integrated speakers and the like. The encodings of the Default Device field are defined in Table 111.

Intel High Definition Audio Specification 1.0a section 7.3.3.31 Configuration Default

Table 111. Default Device

  • Line Out – 0h
  • Speaker – 1h
  • HP Out – 2h
  • CD – 3h
  • SPDIF Out – 4h
  • Digital Other Out – 5h
  • Modem Line Side – 6h
  • Modem Handset Side – 7h
  • Line In – 8h
  • AUX – 9h
  • Mic In – Ah
  • Telephony – Bh
  • SPDIF In – Ch
  • Digital Other In – Dh
  • Reserved – Eh
  • Other – Fh

The Microsoft High Definition Audio class driver hdaudio.sys reads the Configuration Default register, looks at the Default Device, and transforms that into a KSPIN_DESCRIPTOR.Category value. For example, “HP Out” becomes KSNODETYPE_HEADPHONES.

At one time Microsoft had a High Definition Audio Utility (HDAU.exe) which you could use to see the configuration default for the Intel High Definition Audio device in your system. It used IOCTL_AZALIABUS_SENDVERBS to query the Configuration Default register from the Microsoft Intel High Definition Audio class driver hdaudio.sys.

The IOCTL_AZALIABUS_SENDVERBS IOCTL is used by the Hdau.exe pin configuration tool when you define sound topologies for your audio adapters… This IOCTL is supported in the Windows 7 Hdaudio.sys audio class driver.

Communicating Verbs with the HD Audio Codec

Alas, this utility is defunct.

The Hardware Logo Kit (HLK) comes with UAA Test, which (among other things) helps to validate configuration default settings for Intel High Definition Audio devices.

How can my USB audio device tell the audio driver what kind of device it is?

Last time I blogged about how an audio device driver can tell Windows what kind of audio device it is. But how does the driver know? It depends on the driver.

In the case of a USB audio device, there is a hardware specification… or rather, three (so far:)

In USB Audio-speak, the “kind of device” in question is called a “terminal type.” Each of the USB Audio specifications includes the USB Audio Terminal Types specification by reference. for example:

  • USB Audio 1.0 section 5.3.3.1.4 Headphone Input Terminal ID10 Descriptor says Allowed values for the wTerminalType field can be found in the Audio 1.0 Terminal Types Specification.
  • USB Audio 2.0 section 4.7.2.5 Output Terminal Descriptor and
    USB Audio 3.0 section 4.5.2.2 OUTPUT TERMINAL DESCRIPTOR both say A complete list of Terminal Type codes is provided in a separate document, USB Audio Terminal Types that is considered part of this specification.

Terminals can be input, or output, or bi-directional, or… well, a couple other things. Each version of the terminal types specification has a list for each of these. For example, here’s the list of bi-directional terminal types from the USB Audio Terminal Types 3.0 spec:

  • Bi-directional Undefined – 0x0400
  • Handset – 0x0401
  • Headset – 0x0402
  • Speakerphone, no echo reduction – 0x0403
  • Echo-suppressing speakerphone – 0x0404
  • Echo-canceling speakerphone – 0x0405

Microsoft provides a USBView tool which can show you the USB descriptor for any USB device. Here’s a screenshot showing the USB audio terminal types for the USB audio device on my desk:

USBView showing wTerminalType values for a USB audio device

Windows’ USB Audio class driver reads the terminal type from the descriptor, converts it to a Kernel Streaming pin category GUID as listed in ksmedia.h, and reports it to Windows via the KSPIN_DESCRIPTOR for the pin factory corresponding to the terminal.

How can my audio device driver tell Windows what kind of audio device it is?

Last time I blogged about how an application can ask Windows what kind of audio device it is using. But how does Windows know?

Windows has a common Device Driver Interface (DDI) for audio drivers (sound cards) and video capture drivers (webcams) called Kernel Streaming (KS.)

An audio output (like a speaker) or input (like a microphone) or video capture input (like a webcam) is called a “Kernel Streaming pin factory.” The audio device driver or video capture device driver fills out a descriptor for each pin factory, which is a KSPIN_DESCRIPTOR structure.

One of the fields in this structure is Category. To quote from the documentation:

Specifies a pointer to a KS pin category GUID. The KS pin category GUID identifies the general category of functionality that the pin provides. Examples of KS pin category GUIDs are KSNODETYPE_SPEAKER, KSNODETYPE_HEADPHONES, and KSNODETYPE_MICROPHONE, which are all defined in Ksmedia.h. Also see Pin Category Property.

KSPIN_DESCRIPTOR.Category

The Windows Driver Kit comes with ksmedia.h, which has a long list of KSNODETYPE_ values. If you’re writing a driver, this is a good place to see what your options are.

It also comes with a useful utility called Kernel Streaming Studio (KSStudio.exe). This will allow you to see (among other things) the KSPIN_DESCRIPTOR settings for every audio device and video capture device on your system which supports Kernel Streaming. Here’s a screenshot showing that the USB Audio device on my desk advertises KSNODETYPE_SPEAKER and KSNODETYPE_MICROPHONE:

Kernel Streaming Studio (KSStudio.exe) showing KSPIN_DESCRIPTOR.Category

But how does the driver know? It depends on the driver. See:

How can my application tell what kind of audio device it’s using?

There are many kinds of audio devices – speakers, microphones, headsets, cars, TVs, etc.

If you’re writing an app and you want to ask Windows what kind of audio device you’re dealing with, you can use the Windows.Devices.Enumeration APIs on Windows 8 and later. There’s a sample here that shows how to enumerate devices and their properties generically:
https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/DeviceEnumerationAndPairing

Since you’re interested in audio devices specifically, you would use one of the selectors from the Windows.Media.Devices.MediaDevice namespace, e.g. GetDefaultAudioRenderId.

If you are running on Windows 7, that API does not exist, and you have to use the IMMDeviceEnumerator API instead. I have a sample for that here:
https://matthewvaneerde.wordpress.com/2011/06/13/how-to-enumerate-audio-endpoint-immdevice-properties-on-your-system/

Either way, there are two properties of interest to you, depending on the level of granularity you want. (There are also other general properties which may be of interest, e.g. you can use the container ID property to tell whether the audio device is internal or external to the system. This blog post limits itself to the following two audio-specific properties.)

  1. PKEY_AudioEndpoint_FormFactor = “{1DA5D803-D492-4EDD-8C23-E0C0FFEE7F0E} 0”. This is a PROPVARIANT with vt = VT_UI4 and ulVal = some member of the EndpointFormFactor enumerated type.
  2. PKEY_AudioEndpoint_JackSubType = “{1da5d803-d492-4edd-8c23-e0c0ffee7f0e} 8”. Not every audio device has this property, only ones that are backed by Kernel Streaming audio drivers. For such devices, the property is a PROPVARIANT with vt = VT_LPWSTR and pwszVal = one of various GUIDs defined in ksmedia.h, in string form. The GUID names begin with KSNODETYPE_, for example KSNODETYPE_DISPLAYPORT_INTERFACE = {E47E4031-3EA6-418d-8F9B-B73843CCBA97} means that the audio device is connected via a DisplayPort jack, which in turn probably means that the audio device is either a TV or an audio receiver.

But how does Windows know? See How can my audio device driver tell Windows what kind of audio device it is?

What API is being used to play or record audio?

When troubleshooting audio problems it is sometimes interesting to know exactly what audio API the app in question is using.

Sometimes we can just ask the app developer, or look at their code.

Sometimes it is possible to get an educated guess by looking at the list of .dlls that get loaded into the app. But in cases where an app uses multiple audio APIs simultaneously, this doesn’t help much.

The old-school technique, if you have a repro sitting in front of you, is to attach a debugger to the app, set a breakpoint or two, resume, and then once a breakpoint hits, dump the stack. But if you don’t have a repro sitting in front of you, this is difficult.

Fortunately, Event Tracing for Windows (ETW) has a feature that you can ask for the stack at the time a given event was logged! I’ve blogged about this before in Tracking down calls to AvSetMmThreadCharacteristics.

Instructions:

  1. Download audio-client-stack.wprp (right-click the link and save the file rather than opening it in the browser)
  2. From an elevated Command Prompt or PowerShell window:
    wpr.exe -start audio-client-stack.wprp
    (run the app and trigger the audio activity)
    wpr.exe -stop some-filename.etl
  3. Open some-filename.etl in Windows Performance Analyzer
  4. Look at System Activity > Generic Events and System Activity > Stacks. Use Trace > Load Symbols to get function names to resolve.

For example, this is the callstack I get for Microsoft.Windows.Audio.Client/AudioClientInitialize when I do echo ^G (that’s Ctrl-G) from a PowerShell window:

ntdll.dll!RtlUserThreadStart
kernel32.dll!BaseThreadInitThunk
wdmaud.drv!CWorker::_StaticThreadProc
wdmaud.drv!CWorker::_ThreadProc
wdmaud.drv!`CWaveHandle::Open’::`2′::COpenJob::Work
wdmaud.drv!CWaveOutHandle::_Open
wdmaud.drv!CWaveHandle::_Open
AudioSes.dll!CAudioClient::Initialize
AudioSes.dll!CAudioClientTraceLogger::LogInitialize
ntdll.dll!EtwEventWriteTransfer
ntdll.dll!EtwpEventWriteFull
ntdll.dll!ZwTraceEvent

audioclientinitialize-stack

So in the case of echo ^G I can conclude that the API layer immediately above the Windows Audio Session API (WASAPI) is Windows Multimedia (WinMM)‘s Waveform-Audio interface (waveOutOpen), because I happen to know that wdmaud.drv is the module that implements Waveform-Audio.

I can’t tell from this stack alone whether there is another audio API above that (say, PlaySound.) I could repeat this process by finding an event that was logged by waveOutOpen and constructing another .wprp to grab the stack on that thread, and so on and so forth.

If Windows Update sent you Intel Audio Controller version 9.21.0.3755 by mistake, uninstall it

An Intel audio driver was incorrectly pushed to devices via Windows Update for a short period of time earlier this week.  After receiving reports from users that their audio no longer works, we immediately removed it and started investigating.  If your audio broke recently, and you’re running Windows 10 version 1709 or above, please check to see if the incorrect driver was installed. To regain audio, we recommend you uninstall the driver.

  1. Type Device Manager in the search box
  2. Find and expand Sound, video, and game controllers
  3. Look for a Realtek device, or a device that has a yellow triangle with an exclamation point
  4. Click on the device to select it
  5. From the View menu, choose Devices by connection
  6. Look at the parent device – this will be called something like “Intel SST Audio Controller” (Intel Smart Sound Technology driver version 09.21.00.3755)
  7. Right-click the controller device
  8. Choose Properties
  9. You should get a dialog like below. Click on the Driver tab as shown.
  10. If the driver version is 9.21.0.3755, you have the driver that was sent to you incorrectly.
  11. Click Uninstall Device. You will get a popup asking if you want to remove the driver too, as shown.
  12. Check the checkbox as shown, so the driver will be removed.
  13. Click Uninstall.
  14. When the driver is uninstalled, reboot your system.
  15. Your audio (speakers and headphones) should now work.

UPDATE 2018-10-13: Windows Update KB4468550 now removes the driver automatically from systems that received it incorrectly.

UPDATE 2018-10-14: fixed affected versions of Windows

UPDATE 2018-10-26: The initial version of KB4468550 failed to install on Windows 10 systems that were running in S mode. We have released a fixed version of the update under the same KB article number.

Tracking down calls to AvSetMmThreadCharacteristics

Boring introductory stuff first:

Windows Vista introduced a feature called the “Multimedia Class Scheduler Service” (MMCSS). This is designed to give audio and video threads regular, short, bursts of very high priority, so that audio and video can stream without glitching. The bursts are regular so that audio and video packets don’t get delayed, and they are short so that non-multimedia activity doesn’t get starved.

It’s very important to note that apps which called into high-level audio and video APIs (e.g., the <audio> and <video> HTML tags) don’t have to worry about this kind of thing; the implementation of the high-level API takes care of registering the right pieces of its code with MMCSS.

For apps which (for one reason or another) choose not to use the high-level APIs, and instead want to hook into low-level APIs directly, the original design was for the app to call AvSetMmThreadCharacteristics function from its streaming thread when streaming begins, and AvRevertMmThreadCharacteristics when streaming ends.

In Windows 8.1, the Real-Time Work Queue API was created. This is the preferred approach for apps which want to use low-level APIs.

(whew)

Now the good stuff. I got an email from a pro audio application developer who said that AvSetMmThreadCharacteristics was giving an ERROR_TOO_MANY_THREADS error in his app… even though he only registered a single thread with MMCSS! Surely one thread is not too many…

At this point you should pause and read the excellent book One Kitten is Not Too Many. I’ll wait.

Welcome back! A bunch of different theories started popping up in my head, like “maybe some other process on the system is consuming all the MMCSS slots”, or “maybe a plugin for the application is registering threads without the application developer’s knowledge”, or “maybe the call to AvRevertMmThreadCharacteristics isn’t happening”, or “maybe the task handle is being overwritten between Set and Revert”.

But then I remembered Raymond Chen’s advice: Theorize if you want, but if the problem is right there in front of you, why not go for the facts?

MMCSS has “Event Tracing for Windows” (ETW) logging. In particular, when a task is created, the Microsoft-Windows-MMCSS provider logs a Thread_Join event. This will shed light on what processes and threads are registering with MMCSS.

Also, ETW supports grabbing a stack at the point of an event being logged! This will shed light on whether the registration is happening from app code directly, or a plugin, or whatever.

So I sent the developer these instructions:

  1. Download mmcss.wprp (right-click the link and save)
  2. Open an elevated Command Prompt or PowerShell window
  3. Run wpr.exe -start mmcss.wprp
  4. Launch the app
  5. Create some audio objects and let them run for one second or so
  6. Close the app
  7. Run wpr.exe -stop mmcss.etl (you can change the output file name if you like)
  8. Inspect the resulting mmcss.etl file

In my local testing (I just used echo ^G from a command prompt) I was able to see a Microsoft-Windows-MMCSS/Thread_Join/ event with this stack (only the bold part is interesting)

[Root]
  ntdll.dll!RtlUserThreadStart
  kernel32.dll!BaseThreadInitThunk
  wdmaud.drv!CWorker::_StaticThreadProc
  wdmaud.drv!CWorker::_ThreadProc
  wdmaud.drv!`CWaveHandle::Open’::`2′::COpenJob::Work
  wdmaud.drv!CWaveOutHandle::_Open
  wdmaud.drv!CWaveHandle::_Open
  avrt.dll!AvSetMmThreadCharacteristicsA
avrt.dll!AiThreadConnect
avrt.dll!AiCreateMmcssTaskIndexOrThreadClient
ntdll.dll!ZwCreateFile
ntoskrnl.exe!KiSystemServiceCopyEnd
ntoskrnl.exe!NtCreateFile
ntoskrnl.exe!IopCreateFile
ntoskrnl.exe!ObOpenObjectByNameEx
ntoskrnl.exe!ObpLookupObjectName
ntoskrnl.exe!IopParseDevice
ntoskrnl.exe!IoCallDriverWithTracing
ntoskrnl.exe!IofCallDriver
mmcss.sys!CiDispatchCreate
mmcss.sys!CiDispatchCreateMmThreadClient
mmcss.sys!CiThreadCreate
mmcss.sys!CiLogThreadJoin
ntoskrnl.exe!EtwWrite