USB how many samples in 48K?

I am testing my filter driver for USB audio. I couldn’t make it work with upper filter driver so I am working it as a lower filter driver.

Question is that when I record a stream with 48K and stereo data using the USB audio device, I can see that MDL length is 2000 but the buffer length from the header is 480. Which is right? The basic code is shown as below.

struct _URB_ISOCH_TRANSFER *pIsochTransfer = (struct _URB_ISOCH_TRANSFER *) pUrb;

ASSERT( pIsochTransfer->TransferBufferMDL == 2000 );
ASSERT( pIsochTransfer->TransferBufferLength == 1920 );

Also to verify which is right length of buffer, I filled the MDL buffer with zeros( pIsochTransfer->TransferBufferMDL = 0, 2000 samples ) and filled some wierd data to manipulate but the still real data from an application shows that 1920 is right length.

Does this USB audio driver skips some of samples or what??

Thank you.

Pre-Vista and outside of DirectX or Direct Ks apps, anyway, you’ll be dealing with KMixer in the audio graph, which will mean 10 milliseconds of audio data transfer in each IRP. At 48K, this is 480 samples, and assuming you are a 2-channel device with 16 bits of resolution, then your format would be asked for (or given, if playing) 1920 bytes on each IRP presented.

If the MDL is bigger, that’s irrelevant. The URB shouldn’t transfer more than the “transfer buffer length”.

Thank you Bob.

I thought 480 samples is right and easy to calculate. I made a real simple filter driver as I mentioned and filled the buffer with zeros as much as 480 samples but the weird thing is that I can see some of left of data from 500 samples in the test application( wave recording app. ). That’s why I was so puzzled about it. If I clear it up to 500 samples every thing is clean and no leftover data in the application, but not for the 480 samples. Do you have any idea?

Thank you again Bob

Sorry it is not 500 samples it is something like 480+18 samples, which is 498. If I clean up 498 samples, I can see clean 0ed data but If I clean up only 480, some garbage data is there.

Thank you

Which versions of the OS is this occurring on (IIRC, there are three usbaudio drivers in use- 2K/ME/98, XP, and Vista)?
Is this your own recording app, or are you recording with the recording applet or some other known quantity?

Have you used the KS debugger extension to examine the IRPs streaming into your stack? For instance !devstack with your FDO to get the usbaudio FDO, and then !ks.enumdevobj to get the KS filter info, then !ks.dump the filter to get the list of queued IRPs. That and some poking around the IRPS should give you a better idea what is happening.

I’ve spent some time [as in fixing or investigating bugs and some minor enhancements] with portcls/kmixer/sysaudio/wdmaud, and even KS, but unfortunately, not usbaudio itself. So my value in terms of assistance or insight is pretty limited.

I am so sorry for not mentioning the environment. I am tesing it with a typical Windows XP sp2 and using iMic USB audio device.

The basic code frame is that

NTSTATUS DriverEntry ( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath )
{

DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = USBMonInternalIOCTL;

}

NTSTATUS USBMonInternalIOCTL ( IN PDEVICE_OBJECT fdo, IN PIRP Irp )
{

stack = IoGetCurrentIrpStackLocation(Irp);
pdx = (PDEVICE_EXTENSION) fdo->DeviceExtension;
dwControlCode = stack->Parameters.DeviceIoControl.IoControlCode;

if( IOCTL_INTERNAL_USB_SUBMIT_URB == dwControlCode)
{
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp, InternalIOCTLCompletion, …);
ntStatus = IoCallDriver(pdx->LowerDeviceObject, Irp);
}
}

NTSTATUS InternalIOCTLCompletion
(IN PDEVICE_OBJECT fdo, IN PIRP Irp, IN PVOID Context )
{

if ( IOCTL_INTERNAL_USB_SUBMIT_URB == dwControlCode )
{
pUrb = (PURB)stack->Parameters.Others.Argument1;

if(pIsochTransfer->Hdr.Length < sizeof(struct _URB_ISOCH_TRANSFER ))
{
return;

}

bReadFromDevice = (BOOLEAN)(pIsochTransfer->TransferFlags & USBD_TRANSFER_DIRECTION_IN);

<<< do some work for massaging Data. >>>.

}

}

A pretty simple code structure.

First, I want to see if I can put all 0’s in the buffer. So I put all 0’s in the buffer at the length of 480, then some of garbage data come out at the end of 462 samples with the size of 18. But If I clean it with 500 or at least 498(480+18) Everything is cleaned.

Look like below

------------------------------a;skjfeijfiewj------------------------------a;skjfeijfiewj
|<--------1’st frame------------------->|<-------------2’nd frame--------------->|
|<---------------------------------------->| 480 samples
|<------------->| 18 samples

So that’s why I wonder if the USB dvier is skipping data in upper level.

Well, given what you’re now describing it does look like Kmixer-sourced IRPs of 480 samples are what you are processing.

Are you sure you’re not zeroing 18 samples worth of data BEFORE the buffer? How are you determining the address from which you start?

I’m sorry, but I’m not familiar with the USB Audio specs, and haven’t time to change that any time soon- is there any header info in these transfers that you are not accounting for?

Thank you so much for replying.

That’s another wondering part that why 18 samples missing.

Below is the basic code for massaging the data. This in only for the testing.
I verified that the pIsochTransfer->TransferBuffer and pIsochTransfer->TransferBufferMDL has same address and pIsochTransfer->TransferBufferLength is 480 samples.

There must be something that I am missing. Still, wierd part is that If I can make 0’s of 500 samples whether it is important data or not, every data is cleaned. If it is sort of critical data, then I should see the bang, but I didn’t.

MassgeData( (PUCHAR)pIsochTransfer->TransferBuffer, pIsochTransfer->TransferBufferMDL, pIsochTransfer->TransferBufferLength);

void MassageData(PUCHAR pBuffer, PMDL pMdl, ULONG uBufferSize)
{
ULONG itCount;
if(pBuffer) {
if(pMdl) {
// PUINT16 pMDLBuf = (PUINT16)MmGetSystemAddressForMdl(pMdl);
PUINT16 pMDLBuf = (PUINT16)pBuffer;

int iLength = MmGetMdlByteCount(pMdl); // 500 samples
iLength = uBufferSize; // 480 samples

// RtlZeroMemory( pMDLBuf, iLength);

iLength >>= 2; // 16 bits, stereo data

if( iLength >= 480 ) {
if(pMDLBuf) {
for( itCount = 0 ; itCount < iLength; itCount++) {
*pMDLBuf = itCount*40;
pMDLBuf += 2;
}
}
}
}

Thank you again.

OK- I can understand the problem, now- I’ll get back to you after I’ve had a chance to follow up. In the meantime, there’s always hope somebody else may have an answer for you sooner…

Thank you Bob for your continuous replying.

I kind a fiugured out that the USB has buffer limit. So that among 500 samples only 480 samples are used and skipped some part of it. In my case after every 48 samples it skips 2 samples.

Thank you again.
Have a good weekend.