Sysdriver: How to capture Input data and play user audio application data

@Tim_Roberts said:

my device is already registered at 4d36e96c-e325-11ce-bfc1-08002be10318 in registry

That GUID does not belong to you. That’s a Microsoft GUID, and exposing it makes other promises. You need to create your own GUID for your own private interface.

All of the casts you are doing make me suspicious that you’ve made a rookie mistake. You shouldn’t have to cast any of that. Just for now, you should throw out the _tprintf and use straight puts to make absolutely sure you’re getting an ANSI string, and not a Unicode string. Get rid of any casts where you are passing that variable to other APIs. If you get compilation errors, then you are mixing character sets, which is disastrous. That’s especially true for CreateFile. If you have to cast the file name to get it into CreateFile, then you have made a mistake.

How to know who(user app or audio engine) calls IRP_MJ_CREATE

It’s tricky, The most common way is to add a reference string when you create your device interface, and look for that reference string in the file name field when you get the IRP_MJ_CREATE call.

Is your create handler getting called at all? I’m guessing it isn’t, because you would have seen a blue screen. Does your device appear in Device Manager as a sound device?

Hi Tim,

You are right, i have seen bluescreen issue, but my device appear in device manager, and also i can see the virtual mic in my sound control panel, the only issue i am facing is blue screen(thats bcz of PCDispatcher as u mentioned in create function) and CreateFile error.

for CreateFile i removed all the casting:

GUID guid = {0x4d36e96c, 0xe325, 0x11ce, 0xbf, 0xc1, 0x8, 0x0, 0x2b, 0xe1, 0x3, 0x18 };
CONFIGRET cr;
PWSTR DeviceInterfaceList = NULL;
ULONG DeviceInterfaceListLength = 0;

cr = CM_Get_Device_Interface_List_Size(
    &DeviceInterfaceListLength,
    &guid,
    NULL,
    CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES
);

if (cr != CR_SUCCESS) {
    wprintf(L"fail to get interface list size\n");
    return -1;
}

DeviceInterfaceList = (PWSTR)HeapAlloc(
    GetProcessHeap(),
    HEAP_ZERO_MEMORY,
    DeviceInterfaceListLength * sizeof(WCHAR));

if (DeviceInterfaceList == NULL) {
    wprintf(L"allocate interface list buffer fail\n");
    return -2;
}

cr = CM_Get_Device_Interface_List(
    &guid,
    NULL,
    DeviceInterfaceList,/////////////////////////////getting error here:    'function': incompatible types - from 'PWSTR' to 'PZZSTR'
    DeviceInterfaceListLength,
    CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES);

if (cr != CR_SUCCESS) {
    wprintf(L"fail to get interface list\n");
    return -3;
}

wprintf(L"%s\n", DeviceInterfaceList);

HANDLE hDev = INVALID_HANDLE_VALUE;

hDev = CreateFile(
    DeviceInterfaceList,
    FILE_GENERIC_READ,
    0,
    NULL,
    OPEN_EXISTING,
    0,
    NULL
);

if (hDev == INVALID_HANDLE_VALUE) {
    wprintf(L"fail to open device (0x%X)\n", GetLastError());
    return -4;
}

plz help me to resolve ‘function’: incompatible types - from ‘PWSTR’ to ‘PZZSTR’ error in CM_Get_Device_Interface_List function

@chauhan_sumit001 said:

@Tim_Roberts said:

my device is already registered at 4d36e96c-e325-11ce-bfc1-08002be10318 in registry

That GUID does not belong to you. That’s a Microsoft GUID, and exposing it makes other promises. You need to create your own GUID for your own private interface.

All of the casts you are doing make me suspicious that you’ve made a rookie mistake. You shouldn’t have to cast any of that. Just for now, you should throw out the _tprintf and use straight puts to make absolutely sure you’re getting an ANSI string, and not a Unicode string. Get rid of any casts where you are passing that variable to other APIs. If you get compilation errors, then you are mixing character sets, which is disastrous. That’s especially true for CreateFile. If you have to cast the file name to get it into CreateFile, then you have made a mistake.

How to know who(user app or audio engine) calls IRP_MJ_CREATE

It’s tricky, The most common way is to add a reference string when you create your device interface, and look for that reference string in the file name field when you get the IRP_MJ_CREATE call.

Is your create handler getting called at all? I’m guessing it isn’t, because you would have seen a blue screen. Does your device appear in Device Manager as a sound device?

Hi Tim,

You are right, i have seen bluescreen issue, but my device appear in device manager, and also i can see the virtual mic in my sound control panel, the only issue i am facing is blue screen(thats bcz of PCDispatcher as u mentioned in create function) and CreateFile error.

That GUID i have added in INF file .

Is it complaining about PZZSTR, or about PZZWSTR? If it is complaining about PZZSTR, then you have somehow mixed up your APIs, because it means you have the ANSI CM_Get_Device_Interface_List and the Unicode CreateFile. If it is complaining about PZZWSTR, then I will allow you to insert a cast to eliminate that warning. :wink: Just make sure the wprintf prints something readable.

That GUID I have added in INF file.

Why? It doesn’t need to be there. And it’s STILL not your GUID.

@Tim_Roberts said:
Is it complaining about PZZSTR, or about PZZWSTR? If it is complaining about PZZSTR, then you have somehow mixed up your APIs, because it means you have the ANSI CM_Get_Device_Interface_List and the Unicode CreateFile. If it is complaining about PZZWSTR, then I will allow you to insert a cast to eliminate that warning. :wink: Just make sure the wprintf prints something readable.

That GUID I have added in INF file.

Why? It doesn’t need to be there. And it’s STILL not your GUID.

It was complaining about PZZSTR that too inside CM_Get_Device_Interface_List.

GUID guid = { 0x4d36e96c, 0xe325, 0x11ce, 0xbf, 0xc1, 0x8, 0x0, 0x2b, 0xe1, 0x3, 0x18 };

CONFIGRET cr;
LPTSTR  DeviceInterfaceList = NULL;////////////////////////LPTSTR instead of PWSTR
ULONG DeviceInterfaceListLength = 0;

cr = CM_Get_Device_Interface_List_Size(
    &DeviceInterfaceListLength,
    &guid,
    NULL,
    CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES
);

if (cr != CR_SUCCESS) {
    wprintf(L"fail to get interface list size\n");
    return ;
}
DeviceInterfaceList = (LPTSTR)HeapAlloc(//(PZZSTR)HeapAlloc(
    GetProcessHeap(),
    HEAP_ZERO_MEMORY,
    DeviceInterfaceListLength * sizeof(WCHAR));

if (DeviceInterfaceList == NULL) {
    wprintf(L"allocate interface list buffer fail\n");
    return ;
}

cr = CM_Get_Device_Interface_List(
    &guid,
    NULL,
    DeviceInterfaceList,
    DeviceInterfaceListLength,
    CM_GET_DEVICE_INTERFACE_LIST_PRESENT);

if (cr != CR_SUCCESS) {
    wprintf(L"fail to get interface list\n");
   return ;
}

printf("%s\n", DeviceInterfaceList);

HANDLE hDev = INVALID_HANDLE_VALUE;

hDev = CreateFile(
    DeviceInterfaceList,//DeviceInterfaceList,
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_SHARE_READ|FILE_SHARE_WRITE,
    NULL
);

if I declare DeviceInterfaceList as LPTSTR instead of PWSTR its compiling and , value of DeviceInterfaceList also gettingprinted as

\?\ROOT#UNNAMED_DEVICE#0001#{4d36e96c - e325 - 11ce - bfc1 - 08002be10318}

is it fine???

@Tim_Roberts said:
Is it complaining about PZZSTR, or about PZZWSTR? If it is complaining about PZZSTR, then you have somehow mixed up your APIs, because it means you have the ANSI CM_Get_Device_Interface_List and the Unicode CreateFile. If it is complaining about PZZWSTR, then I will allow you to insert a cast to eliminate that warning. :wink: Just make sure the wprintf prints something readable.

That GUID I have added in INF file.

Why? It doesn’t need to be there. And it’s STILL not your GUID.

It was complaining about PZZSTR that too inside CM_Get_Device_Interface_List ,

then I changed the variable DeviceInterfaceList type from PWSTR to LPTSTR

GUID guid = { 0x01ee4b4f, 0x6fb0, 0x4763, 0xa8, 0x43, 0x41, 0x55, 0x91, 0xf1, 0xf0, 0x1 };

CONFIGRET cr;
LPTSTR  DeviceInterfaceList = NULL;
ULONG DeviceInterfaceListLength = 0;

cr = CM_Get_Device_Interface_List_Size(
    &DeviceInterfaceListLength,
    &guid,
    NULL,
    CM_GET_DEVICE_INTERFACE_LIST_ALL_DEVICES
);

if (cr != CR_SUCCESS) {
    wprintf(L"fail to get interface list size\n");
    return ;
}
DeviceInterfaceList = (LPTSTR)HeapAlloc(//(PZZSTR)HeapAlloc(
    GetProcessHeap(),
    HEAP_ZERO_MEMORY,
    DeviceInterfaceListLength * sizeof(WCHAR));

if (DeviceInterfaceList == NULL) {
    wprintf(L"allocate interface list buffer fail\n");
    return ;
}

cr = CM_Get_Device_Interface_List(
    &guid,
    NULL,
    DeviceInterfaceList,
    DeviceInterfaceListLength,
    CM_GET_DEVICE_INTERFACE_LIST_PRESENT);

if (cr != CR_SUCCESS) {
    wprintf(L"fail to get interface list\n");
   return ;
}

printf("%s\n", DeviceInterfaceList);
HANDLE hDev = INVALID_HANDLE_VALUE;

hDev = CreateFile(
    DeviceInterfaceList,//DeviceInterfaceList,
    GENERIC_READ | GENERIC_WRITE,
    0,
    NULL,
    OPEN_EXISTING,
    FILE_SHARE_READ|FILE_SHARE_WRITE,
    NULL
);

got DeviceInterfaceList as \?\ROOT#UNNAMED_DEVICE#0001#{01ee4b4f-6fb0-4763-a843-415591f1f001}

Is it fine , need your approval

You don’t need MY approval, you need WINDOWS’ approval. Does your CreateFile call get into the driver now?

@Tim_Roberts said:
You don’t need MY approval, you need WINDOWS’ approval. Does your CreateFile call get into the driver now?

that i still need to check.

but one more help i already asked, need solution

NTSTATUS IoctlCreateClose(In DEVICE_OBJECT* _DeviceObject,
Inout IRP* _Irp)
{
UNREFERENCED_PARAMETER(_DeviceObject);

PIO_STACK_LOCATION stackLocation = NULL;
stackLocation = IoGetCurrentIrpStackLocation(_Irp);
stackLocation->FileObject->FileName == 
switch (stackLocation->MajorFunction)
{
case IRP_MJ_CREATE:
	DbgPrint("Handle to symbolink link  opened");
	break;
case IRP_MJ_CLOSE:
	DbgPrint("Handle to symbolink link closed");
	break;
default:
	break;
}
_Irp->IoStatus.Information = 0;
_Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(_Irp, IO_NO_INCREMENT);
////PcDispatchIrp(_DeviceObject, _Irp);

return STATUS_SUCCESS;

}

how to knoe that user application calls this api, so that in that case i can avoid PcDispatchIrp

without PcDispatchIrp call here, i couldnot see virtual mic in sound control panel, how to proceed for now

Hi Tim,

For now i have only added PcDispatchIrp and commented IoCompleteRequest(_Irp, IO_NO_INCREMENT); part in IRP_MJ_CREATE handler function still my CreateFile returns FILE_NOT_FOUND error number 2.

some bug in my code that you can only identify sir.

Any help on above post…thanks in advance

Hi Tim,

inside IRP_MJ_CREATE handler function for now i commented PcDispatchIrp(_DeviceObject, _Irp);

with that Createfile is working, but i am not able to see virtual device sound control panel.
while it is visible in device manager.

so plz help me how i can have both PcDispatchIrp(_DeviceObject, _Irp); and IoCompleteRequest(_Irp, IO_NO_INCREMENT); in IRP_MJ_CREATE handler. under condition that when user app call IRP_MJ_CREATE it should skip PcDispatchIrp(_DeviceObject, _Irp);

NTSTATUS IoctlCreateClose(In DEVICE_OBJECT* _DeviceObject,
Inout IRP* _Irp)
{
UNREFERENCED_PARAMETER(_DeviceObject);

PIO_STACK_LOCATION stackLocation = NULL;
stackLocation = IoGetCurrentIrpStackLocation(_Irp);

switch (stackLocation->MajorFunction)
{
case IRP_MJ_CREATE:
	DbgPrint("Handle to symbolink link  opened");
	break;
case IRP_MJ_CLOSE:
	DbgPrint("Handle to symbolink link closed");
	break;
default:
	break;
}

_Irp->IoStatus.Information = 0;
_Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(_Irp, IO_NO_INCREMENT);
//PcDispatchIrp(_DeviceObject, _Irp);////////////////////////how to keep this also

return STATUS_SUCCESS;

}

@chauhan_sumit001 said:
Any help on above post…thanks in advance

my createfile is working now,after commenting pcdispatcher from IRP_MJ_CREATE handler, but i want PCDispatcher also,how to do that

I did tell you that earlier in the thread. Port Class uses the file name in the IRP_MJ_CREATE IRP to decide what kind of open it is. You can dump those file names in the debugger to see what they look like. You can add a reference string to your device interface, and that reference string will be passed as the file name. If you use a custom reference string, then you can identify when the open comes from your application.

Hi Tim,

Plz give some clue on above post.

@Tim_Roberts said:
I did tell you that earlier in the thread. Port Class uses the file name in the IRP_MJ_CREATE IRP to decide what kind of open it is. You can dump those file names in the debugger to see what they look like. You can add a reference string to your device interface, and that reference string will be passed as the file name. If you use a custom reference string, then you can identify when the open comes from your application.

Hi Tim,

I have one doubt, you have mentioned about “add a reference string to your device interface”

Is it the same reference string which we pass inside

UNICODE_STRING device_sym_link = RTL_CONSTANT_STRING(L"\Device\RemotePCVadDevice");
UNICODE_STRING device_ref_string = RTL_CONSTANT_STRING(L"RemotePCVadDevice");

ntStatus = IoRegisterDeviceInterface(
PhysicalDeviceObject,
&RPC_IOCTL_AUDIO,
&device_ref_string,/////////////////are u talking about this???plz clarify
&device_sym_link
);

if yes then we can use

const auto IsUserSpaceAppRequest =
!RtlCompareUnicodeString(&device_ref_string
, &IrpStack->FileObject->FileName
, TRUE);

to identify the call inside IRP_MJ_CREATE

In CreateFile I am passing “\?\ROOT#MEDIA#0007#{4d36e96c-e325-11ce-bfc1-08002be10318}\RemotePCVadDevice” as file name

plz clarify.

Yes, that’s it. I don’t remember whether the driver gets a leading "" or not; you’ll have to do some debug prints to verify that.

Hi Tim,

over the TCP connection I am receiving encoded mic output from source application ,at target app i am decoding the audio data , now
I have decoded audio data(using AAC) in my target application, that I want to redirect to virtual audio mic(earlier i was playing it using SDL player). do I need to store that decoded data again in ring buffer within the driver code??,

I can transfer that decode data to driver using IOCTL, but there I will receive inside driver.cpp custom IOCTL handler, from custom IOCTL handler how can I transfer the data to MiniportWaveRTStream::WriteBytes and copy it to m_pDmaBuffer. plz help with some sample code snippet.

VOID MiniportWaveRTStream::WriteBytes
(
In ULONG ByteDisplacement
)
/*++

Routine Description:

This function writes the audio buffer using a sine wave generator
Arguments:

ByteDisplacement - # of bytes to process.

–*/
{

ULONG bufferOffset = m_ullLinearPosition % m_ulDmaBufferSize;

//// Normally this will loop no more than once for a single wrap, but if
//// many bytes have been displaced then this may loops many times.
while (ByteDisplacement > 0)
{
	ULONG runWrite = min(ByteDisplacement, m_ulDmaBufferSize - bufferOffset);
	SIZE_T actuallyWritten;
	
	m_RingBuffer->Take(m_pDmaBuffer + bufferOffset, runWrite, &actuallyWritten);
	if (actuallyWritten < runWrite)
	{
		RtlZeroMemory(m_pDmaBuffer + bufferOffset + actuallyWritten, runWrite - actuallyWritten);
	}
	
	bufferOffset = (bufferOffset + runWrite) % m_ulDmaBufferSize;
	ByteDisplacement -= runWrite;
}

}

if i have to feed my audio buffer to m_pDmaBuffer , do i need to write that much code inside WriteBytes(mentioned above), except
memcpy(m_pDmaBuffer ,my audio buffer received USING IOCTL, length)???

plz need your help.

Hi , Any suggestion on above post.

Any suggestion on above post.

Here’s one suggestion. Be patient, damn it. You posted this on Sunday afternoon here in the US, then prodded when you didn’t get a reply in 6 hours.
Most of us who do this for a living aren’t working on Sundays. We don’t need you to demand results.

I can transfer that decode data to driver using IOCTL, but there I will receive inside driver.cpp custom IOCTL handler,
from custom IOCTL handler how can I transfer the data to MiniportWaveRTStream::WriteBytes and copy it to m_pDmaBuffer.

Your ioctl handler needs to copy your data into the circular buffer. You shouldn’t need to change WriteBytes; it already knows how to read from the circular buffer. The only tricky part is finding the MiniPortWaveRTStream device so you can access its m_pDmaBuffer. That’s just a matter of following the pointers for the objects you do have.

@chauhan_sumit001 said:
Hi Tim,

over the TCP connection I am receiving encoded mic output from source application ,at target app i am decoding the audio data , now
I have decoded audio data(using AAC) in my target application, that I want to redirect to virtual audio mic(earlier i was playing it using SDL player). do I need to store that decoded data again in ring buffer within the driver code??,

I can transfer that decode data to driver using IOCTL, but there I will receive inside driver.cpp custom IOCTL handler, from custom IOCTL handler how can I transfer the data to MiniportWaveRTStream::WriteBytes and copy it to m_pDmaBuffer. plz help with some sample code snippet.

VOID MiniportWaveRTStream::WriteBytes
(
In ULONG ByteDisplacement
)
/*++

Routine Description:

This function writes the audio buffer using a sine wave generator
Arguments:

ByteDisplacement - # of bytes to process.

–*/
{

ULONG bufferOffset = m_ullLinearPosition % m_ulDmaBufferSize;

//// Normally this will loop no more than once for a single wrap, but if
//// many bytes have been displaced then this may loops many times.
while (ByteDisplacement > 0)
{
ULONG runWrite = min(ByteDisplacement, m_ulDmaBufferSize - bufferOffset);
SIZE_T actuallyWritten;

  m_RingBuffer->Take(m_pDmaBuffer + bufferOffset, runWrite, &actuallyWritten);
  if (actuallyWritten < runWrite)
  {
  	RtlZeroMemory(m_pDmaBuffer + bufferOffset + actuallyWritten, runWrite - actuallyWritten);
  }
  
  bufferOffset = (bufferOffset + runWrite) % m_ulDmaBufferSize;
  ByteDisplacement -= runWrite;

}
}

if i have to feed my audio buffer to m_pDmaBuffer , do i need to write that much code inside WriteBytes(mentioned above), except
memcpy(m_pDmaBuffer ,my audio buffer received USING IOCTL, length)???

plz need your help.

Hi All,

I am stuck at one point, i want to access ringbuffer and feed the data received from IOCTL inside IOCTL handler from user application, but currenly my ringbuffer is inside MiniportWaveRTStream class where inside WriteBytes I am taking data from ringbuffer and feeding it to dma buffer, so how can I access the same ringbuffer inside my IOCTL handler in adapter.cpp in SYSVAD class to put the data. plz provide some code snippet.

need your help badly…

@Tim_Roberts said:

Any suggestion on above post.

Here’s one suggestion. Be patient, damn it. You posted this on Sunday afternoon here in the US, then prodded when you didn’t get a reply in 6 hours.
Most of us who do this for a living aren’t working on Sundays. We don’t need you to demand results.

I can transfer that decode data to driver using IOCTL, but there I will receive inside driver.cpp custom IOCTL handler,
from custom IOCTL handler how can I transfer the data to MiniportWaveRTStream::WriteBytes and copy it to m_pDmaBuffer.

Your ioctl handler needs to copy your data into the circular buffer. You shouldn’t need to change WriteBytes; it already knows how to read from the circular buffer. The only tricky part is finding the MiniPortWaveRTStream device so you can access its m_pDmaBuffer. That’s just a matter of following the pointers for the objects you do have.

Hi Tim,

I am extremely sorry for being impatient, it was not at all intended.

If I understood your point correctly, then I should not create one more ringbuffer inside driver class to store my audio data received using IOCTL handler.

is m_pDmaBuffer is circular buffer???

if yes then directly I can copy my data to m_pDmaBuffer. is that correct???