Capture USB audio

63 views
Skip to first unread message

Wolfgang Wallhäuser

unread,
Jun 2, 2019, 12:30:46 PM6/2/19
to USBPcap
I’m hunting echo issues with certain USB headsets. I would like to capture USB audio transmitted to and received from the headset. Then I could compare this recording to recordings from my VoIP application. 

I wrote a simple c++ application that parses the USBPcap capture file (pcap format), searches for URB_FUNCTION_ISOCH_TRANSFER packets and dumps all audio samples into two wave files (input, output). This works well for audio in: The dumped wave file contains the correct audio capture from the USB headset. But the parser finds none URB_FUNCTION_ISOCH_TRANSFER  OUT packets containing data. All URB_FUNCTION_ISOCH_TRANSFER OUT packets have a reported size of 159 bytes, while the URB_FUNCTION_ISOCH_TRANSFER IN have a reported size of 479 bytes. 

For IN packets, the USBPCAP_BUFFER_ISOCH_HEADER is followed by 10 USBPCAP_BUFFER_ISO_PACKET with correct offset and length. For OUT packets, dataLength is 0 and all following 10 USBPCAP_BUFFER_ISO_PACKET structures have a reported length of 0.

When I open the file in Wireshark, it just looks the same: URB_FUNCTION_ISOCH_TRANSFER IN contains data, URB_FUNCTION_ISOCH_TRANSFER  OUT does not contain data.

USBPcap 1.4 or 1.3, Wireshark 3.02, Windows 10 - 17763, x64, Jabra Evolve headset.

Do you have any hints for capturing audio out data?

Wolfgang

Tomasz Moń

unread,
Jun 3, 2019, 1:18:32 AM6/3/19
to Wolfgang Wallhäuser, USBPcap
On Sun, Jun 2, 2019 at 6:30 PM 'Wolfgang Wallhäuser' via USBPcap
<usb...@googlegroups.com> wrote:
> USBPcap 1.4 or 1.3, Wireshark 3.02, Windows 10 - 17763, x64, Jabra Evolve headset.
>
> Do you have any hints for capturing audio out data?

Could you please try with USBPcap 1.2.0.4?

There was a fix for ISOCH IN in 1.3.0.0 release. So the IN transfer
will most likely be wrong with 1.2.0.4, but it'd be good to know if
the OUT transfers are correctly captured in 1.2.0.4 (and if they are,
what does their header look like).

Tomasz Moń

unread,
Jun 3, 2019, 2:17:04 AM6/3/19
to Wolfgang Wallhäuser, USBPcap
Page [1] states "For isochronous OUT transfers, the driver stack
ignores the value that is set in IsoPacket[i].Length.".

It looks that I have noticed this earlier, as the capture format page
contains "packet[x].length is not used for isochronous OUT transfers".
It slip out of my radar when reviewing the fix for isochronous IN
packets [2] and thus the fix for IN packets, breaks the capture of OUT
packets. Namely, the fix treats both IN and OUT transfers the same,
while it should not rely on the IsoPacket[i].Length field for OUT
transfers.

Could you please confirm that the OUT data looks correct when captured
using USBPcap 1.2.0.4? Are there any empty gaps in between the
isochronous data? (as I understand the documentation there shouldn't
be)

[1] https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/transfer-data-to-isochronous-endpoints
[2] https://github.com/desowin/usbpcap/pull/67

Wolfgang Wallhäuser

unread,
Jun 3, 2019, 4:28:12 AM6/3/19
to USBPcap
Yes, USBPcap 1.2.0.4 (containing driver 1.3.0.3) captures isochronous OUT data. As you already stated, the ISO data length is always 0. Packet Data Length is 1920. When I ignore ISO data length and use 0xc0 instead for isochronous OUT data, it works. isochronous IN data works as well.

I tested with Jabra Speak 410:
- Play test sound via Windows sound control panel
- Test microphone level via Windows sound control panel.

For both tests I could extract correct wave files.

Wolfgang

Wolfgang Wallhäuser

unread,
Jun 3, 2019, 9:18:06 AM6/3/19
to USBPcap
I have tested more devices. It turns out that the packet data length differs for the different devices.

When I use "pIsoChronousHeader->packet[1].offset" as ISO data length for isochronous OUT data, it works.

My current solution for extracting audio out:


        streampos fileSize;
        ifstream file(pCapFileName, ios::binary);

        file.seekg(0, ios::end);
        fileSize = file.tellg();
        file.seekg(0, ios::beg);

        if (fileSize < sizeof(pcap_hdr_t)) return false;

        const size_t bufferSize = 4096;
        char* buffer = (char*)malloc(bufferSize);
        if (buffer == NULL) return false;

        // read file header
        file.read((char*)buffer, sizeof(pcap_hdr_t));
        if (file.fail()) return false;

        pcap_hdr_t* pCapFileHeader = (pcap_hdr_t*)buffer;

        const _int32 bitsPerSample = 16;


        do
        {
            //read recorded packet header
            file.read((char*)buffer, sizeof(pcaprec_hdr_t));
            if (file.fail()) break;

            pcaprec_hdr_t* pRecPacketHeader = (pcaprec_hdr_t*)buffer;
            UINT32 packetLengthRecorded = pRecPacketHeader->incl_len;
            UINT32 packetLengthOriginal = pRecPacketHeader->orig_len;

            if (packetLengthRecorded > bufferSize) break;

            //read recorded packet data
            file.read((char*)buffer, packetLengthRecorded);
            if (file.fail()) break;

            PUSBPCAP_BUFFER_PACKET_HEADER pUsbPacketHeader = (PUSBPCAP_BUFFER_PACKET_HEADER)buffer;

            if (pUsbPacketHeader->function != 0x000a) continue; //URB_FUNCTION_ISOCH_TRANSFER

            if (pUsbPacketHeader->transfer != USBPCAP_TRANSFER_ISOCHRONOUS) continue;
            //if (pUsbPacketHeader->status != 0) continue;

            bool isToHost = ((pUsbPacketHeader->info & 0x01) == 0x01);
            bool isToDevice = !isToHost;
            int busId = pUsbPacketHeader->bus;
            int deviceId = pUsbPacketHeader->device;
            int endpointId = pUsbPacketHeader->endpoint & 0x0f;
            bool isEndPointDirectionInput = (pUsbPacketHeader->endpoint & 0x80) == 0x80;
            bool isEndPointDirectionOutput = !isEndPointDirectionInput;

            bool isWaveIn = isToHost && isEndPointDirectionInput;
            bool isWaveOut = isToDevice && isEndPointDirectionOutput;

            bool hasData = pUsbPacketHeader->dataLength != 0;

            if (!hasData) continue;
            if (!isWaveIn && !isWaveOut) continue;


            PUSBPCAP_BUFFER_ISOCH_HEADER pIsoChronousHeader = (PUSBPCAP_BUFFER_ISOCH_HEADER)buffer;


            char* pSampleDataRoot = buffer + sizeof(USBPCAP_BUFFER_ISOCH_HEADER) + sizeof(USBPCAP_BUFFER_ISO_PACKET) * (pIsoChronousHeader->numberOfPackets - 1);

            auto defaultLengthOfWaveOutIsoPacket = 0;

            if (pIsoChronousHeader->numberOfPackets > 1)
            {
                defaultLengthOfWaveOutIsoPacket = pIsoChronousHeader->packet[1].offset;
            }


            for (auto idx = 0; idx < pIsoChronousHeader->numberOfPackets; idx++)
            {
                PUSBPCAP_BUFFER_ISO_PACKET pIsoPacket = &(pIsoChronousHeader->packet[idx]);
               
            //if (pIsoPacket->status != 0) continue;
               
            if (pIsoPacket->length == 0)
            {
               if (isWaveIn) continue;

               pIsoPacket->length = defaultLengthOfWaveOutIsoPacket;
            }

                auto sampleCount = pIsoPacket->length * 8 / bitsPerSample;

                for (auto idxSample = 0; idxSample < sampleCount; idxSample++)
                {
                    __int16* pSample = (__int16*)(pSampleDataRoot + pIsoPacket->offset + idxSample * sizeof(__int16));
                    __int16 sampleValue = *pSample;

                    if (isWaveIn)
                    {
                        write_word(waveInFile, (int)(sampleValue), 2);
                    }
                    else
                    {
                        write_word(waveOutFile, (int)(sampleValue), 2);
                    }
                }
            }

        } while (true);


Wolfgang

Wolfgang Wallhäuser

unread,
Jun 3, 2019, 9:55:29 AM6/3/19
to USBPcap
With this code I can extract played audio / isochronous OUT from multiple devices when captured by USBPcap v1.2.0.4.
I don't see any gaps.

Recorded audio / isochronous IN works for some devices. For some other devices the extraced audio from isochronous IN is distorted. This could be related to the bugfix you have mentioned for USBPcap v1.3.0.0.

Wolfgang

Tomasz Moń

unread,
Jun 5, 2019, 11:22:13 AM6/5/19
to Wolfgang Wallhäuser, USBPcap
On Mon, Jun 3, 2019 at 3:55 PM 'Wolfgang Wallhäuser' via USBPcap
<usb...@googlegroups.com> wrote:
> With this code I can extract played audio / isochronous OUT from multiple devices when captured by USBPcap v1.2.0.4.
> I don't see any gaps.
>
> Recorded audio / isochronous IN works for some devices. For some other devices the extraced audio from isochronous IN is distorted. This could be related to the bugfix you have mentioned for USBPcap v1.3.0.0.

Could you please check if both isochronous IN and OUT data is captured
correctly with just released USBPcap 1.4.1.0?

Wolfgang Wallhäuser

unread,
Jun 6, 2019, 8:06:39 AM6/6/19
to USBPcap
Thanks for your help, I appreciate your quick response!

Yes, the new release 1.4.1.0 captures isochronous IN and OUT data. I tested it with different devices and will do more tests.

Wolfgang

Wolfgang Wallhäuser

unread,
Jun 6, 2019, 10:23:08 AM6/6/19
to USBPcap
I have now tested 13 devices of three manufacturers and it worked for all cases.

Wolfgang
Reply all
Reply to author
Forward
0 new messages