avstream audio driver volume problem

Hi,

i am new to AVStream and WDM framework.
i am developing a vender specific USB Audio Client driver.

i have a problem during my audio volume implementation.

i have developed the get and set property for KSPROPERTY_AUDIO_VOLUMELEVEL.
i am getting get and set values from the device and filling into the IN OUT PVOID DATA of the get and set handler.

the problem is that when i am going to test it by control panel >sound and audio devices>audio>sound recording and select my device and click on the volume.
the volume slider for my device is opened and when i change it ,the values getting change but it again go back to there maximum position.

can any one give me the idea why its going back to the maximum position.

thanks in advance

hi

i am implementing this driver for Xp.

can anyone know why my slider change there position despite the value is change in my driver.

xxxxx@lntinfotech.com wrote:

i am new to AVStream and WDM framework.
i am developing a vender specific USB Audio Client driver.

i have a problem during my audio volume implementation.

i have developed the get and set property for KSPROPERTY_AUDIO_VOLUMELEVEL.
i am getting get and set values from the device and filling into the IN OUT PVOID DATA of the get and set handler.

the problem is that when i am going to test it by control panel >sound and audio devices>audio>sound recording and select my device and click on the volume.
the volume slider for my device is opened and when i change it ,the values getting change but it again go back to there maximum position.

can any one give me the idea why its going back to the maximum position.

You’re sure that you’re handling both “get” and “set”? Did you set up
the minimum and maximum values in the property description?


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

yes i am handling the set and get in the support handler and getting the KdPrint value which is correct in the device side also but my slider goes up and the get value is not the maximum value but the value which i selected.

i have posted my support handler and get and set handleralso

DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_AUDIO_VOLUMELEVEL, // property item defined in ksmedia.h
PropertyAudioVolume, // our “get” property handler
sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), // minimum buffer length for property
sizeof(ULONG), // minimum buffer length for returned data
PropertyAudioVolume, // our “set” property handler
NULL, // default values
0, // related properties
NULL,
SupportVolumeLevel, // no raw serialization handler
0 // don’t serialize
)

in my SupportVolumeLevel function i am getting the maximum and minimum values from the device.
and i am getting the correct value whice i send from the device.

this is my SupportVolumeLevel function.

{

NTSTATUS Status;

PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

VOLUMELEVELSUPPORT volumeSupport;
KSPROPERTY_DESCRIPTION propDesc;
KSPROPERTY_MEMBERSHEADER members;
KSPROPERTY_STEPPING_LONG range;

ULONG fullPropertySize = sizeof(KSPROPERTY_DESCRIPTION) +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_STEPPING_LONG);

propDesc.AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET |
KSPROPERTY_TYPE_SET;

propDesc.DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION) +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_STEPPING_LONG);

propDesc.PropTypeSet.Set = KSPROPTYPESETID_General;
propDesc.PropTypeSet.Id = VT_I4;
propDesc.PropTypeSet.Flags = 0;
propDesc.MembersListCount = 1;
propDesc.Reserved = 0;

members.MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
members.MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
members.MembersCount = 1;
members.Flags = 0;

CCaptureFilter::ptr_CAVRequest->GetVolMinMax(&CCaptureFilter::ptr_CAVRequest->vol_min,
&CCaptureFilter::ptr_CAVRequest->vol_max,
&CCaptureFilter::ptr_CAVRequest->vol_res,
CCaptureFilter::ptr_Device);

range.SteppingDelta = CaptureFilter::ptr_CAVRequest->vol_res;
range.Bounds.SignedMinimum =CCaptureFilter::ptr_CAVRequest->vol_min;
range.Bounds.SignedMaximum = CCaptureFilter::ptr_CAVRequest->vol_max;

volumeSupport.propDesc = propDesc;
volumeSupport.members = members;
volumeSupport.range = range;

if ( sizeof(ULONG) > ulOutputBufferLength )
{ // No useful buffer. Return info about the requested size and an error.
pIrp->IoStatus.Information = fullPropertySize;
Status = STATUS_BUFFER_TOO_SMALL;

}
else
{

Status = STATUS_SUCCESS;
if ( sizeof(ULONG) <= ulOutputBufferLength )
{
// Should only be Access flags
pIrp->IoStatus.Information = sizeof(ULONG);

if ( sizeof( KSPROPERTY_DESCRIPTION ) <= ulOutputBufferLength )
{
// Just the PropDesc at this level.

*((PKSPROPERTY_DESCRIPTION)Data) = propDesc;
pIrp->IoStatus.Information = sizeof(KSPROPERTY_DESCRIPTION );

if ( fullPropertySize <= ulOutputBufferLength )
{ // All of it.

*((PVOLUMELEVELSUPPORT)Data) = volumeSupport;
pIrp->IoStatus.Information = fullPropertySize ;

}
}
}
}

return Status;

}

and in my get and set handler function is
NTSTATUS
PropertyAudioVolume
(
IN PIRP pIrp,
IN PKSPROPERTY property,
IN OUT PVOID audvol
)
{
PAGED_CODE ();

NTSTATUS Status;
PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation( pIrp );
ULONG ulOutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
PKSFILTER KsFilter = KsGetFilterFromIrp(pIrp);

CCaptureFilter::ptr_CAVRequest->req_params_obj.pdatabuffer=audvol;
CCaptureFilter::ptr_CAVRequest->req_params_obj.length=2;
CCaptureFilter::ptr_CAVRequest->req_params_obj.icontrol=VOLUME;
CCaptureFilter::ptr_CAVRequest->req_params_obj.unitID = CCaptureFilter::ptr_CAVRequest->usb_des.pconfig_desc_comp->aud_ctrl_feature_unit.bUnitID;

Status = ValidatePropertyParams(ulOutputBufferLength,
sizeof(ULONG),
sizeof(LONG));

if (NT_SUCCESS(Status)){

if(property->Flags & KSPROPERTY_TYPE_SET){
// set property

CCaptureFilter::ptr_CAVRequest->req_params_obj.irequest=SET_CUR;
CCaptureFilter::ptr_CAVRequest->req_params_obj.direction= USB_TRANSFER_DIRECTION_OUT;

}
else if(property->Flags & KSPROPERTY_TYPE_GET){
//get property

CCaptureFilter::ptr_CAVRequest->req_params_obj.irequest=GET_CUR;
CCaptureFilter::ptr_CAVRequest->req_params_obj.unitID = CCaptureFilter::ptr_CAVRequest->usb_des.pconfig_desc_comp->aud_ctrl_feature_unit.bUnitID;
CCaptureFilter::ptr_CAVRequest->req_params_obj.direction= USB_TRANSFER_DIRECTION_IN;
}

Status = CCaptureFilter::ptr_CAVRequest->InitiateAudioControlRequest(&CCaptureFilter::ptr_CAVRequest->req_params_obj,
CCaptureFilter::ptr_Device);
KdPrint((“audvol =0x%x\n”,*(PLONG)audvol));
pIrp->IoStatus.Information = ulOutputBufferLength;
}

return Status;

}

do i need to implement the EVENT KSEVENTSETID_AudioControlChange for audio volume.

xxxxx@lntinfotech.com wrote:

yes i am handling the set and get in the support handler and getting the KdPrint value which is correct in the device side also but my slider goes up and the get value is not the maximum value but the value which i selected.

i have posted my support handler and get and set handleralso

DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_AUDIO_VOLUMELEVEL, // property item defined in ksmedia.h
PropertyAudioVolume, // our “get” property handler
sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), // minimum buffer length for property
sizeof(ULONG), // minimum buffer length for returned data
PropertyAudioVolume, // our “set” property handler
NULL, // default values
0, // related properties
NULL,
SupportVolumeLevel, // no raw serialization handler
0 // don’t serialize
)

Since you have a single stepped range, why did you write a support
handler instead of just providing a KSPROPERTY_VALUES structure and
letting AVStream handle it for you?

in my SupportVolumeLevel function i am getting the maximum and minimum values from the device.
and i am getting the correct value whice i send from the device.

this is my SupportVolumeLevel function.

CCaptureFilter::ptr_CAVRequest->GetVolMinMax(&CCaptureFilter::ptr_CAVRequest->vol_min. &CCaptureFilter::ptr_CAVRequest->vol_max,
&CCaptureFilter::ptr_CAVRequest->vol_res,
CCaptureFilter::ptr_Device);

range.SteppingDelta = CaptureFilter::ptr_CAVRequest->vol_res;
range.Bounds.SignedMinimum =CCaptureFilter::ptr_CAVRequest->vol_min;
range.Bounds.SignedMaximum = CCaptureFilter::ptr_CAVRequest->vol_max;

It’s interesting that you chose not to tell us what the actual values
for vol_min, vol_max and vol_res are. What I was trying to explore was
the possibility that your range was actually inverted, and the only way
to check that is to know the actual numbers.

Is “CCaptureFilter::ptr_CAVRequest” a global variable (or a class
static)? That’s not a very good design. What happens if you get
several volume requests for multiple instances at the same time? This
would be easier to read if you made this a member function and had a
static bridge, like

NTSTATUS SupportVolumeFunction( PIRP irp, PKSIDENTIFIER request,
PVOID data )
{
PKSFILTER KsFilter = KsGetFilterFromIrp( irp );
CCaptureFilter* Filter = (CCaptureFilter*)GetFilterFromIrp(
KsFilter->Context );
return Filter->VolumeSupport( irp, request, data );
}

NTSTATUS CCaptureFilter::VolumeSupport( PIRP irp, PKSIDENTIFIER
request, PVOID data )
{

}

CCaptureFilter::ptr_CAVRequest->req_params_obj.pdatabuffer=audvol;
CCaptureFilter::ptr_CAVRequest->req_params_obj.length=2;
CCaptureFilter::ptr_CAVRequest->req_params_obj.icontrol=VOLUME;
CCaptureFilter::ptr_CAVRequest->req_params_obj.unitID = CCaptureFilter::ptr_CAVRequest->usb_des.pconfig_desc_comp->aud_ctrl_feature_unit.bUnitID;

Status = ValidatePropertyParams(ulOutputBufferLength,
sizeof(ULONG),
sizeof(LONG));

This property accepts a “long”, but you’re only fetching two bytes from
the hardware. Since the gain is often a signed value, you need to
sign-extend the result. That’s probably your trouble. Example:

short TempVolume;
CCaptureFilter::ptr_CAVRequest->req_params_obj.pdatabuffer =
&TempVolume;
CCaptureFilter::ptr_CAVRequest->req_params_obj.length = 2;

CCaptureFilter::ptr_CAVRequest->InitiateAudioControlRequest( … );
// Sign-extend the short to a long.
*audvol = TempVolume.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

thanks Tim for your useful information
as you said to implement KSPROPERTY_VALUES

Since you have a single stepped range, why did you write a support handler instead of just >providing a KSPROPERTY_VALUES structure and letting AVStream handle it for you?

i have implemented this also but my volume mixer is disable i cant scroll up or down.
my implementation is below:

DEFINE_KSPROPERTY_ITEM
(
KSPROPERTY_AUDIO_VOLUMELEVEL, // property item defined in ksmedia.h
PropertyAudioVolume, // our “get” property handler
sizeof(KSNODEPROPERTY_AUDIO_CHANNEL), // minimum buffer length for property
sizeof(ULONG), // minimum buffer length for returned data
PropertyAudioVolume, // our “set” property handler
&VolumeValues, // default values
0, // related properties
NULL,
NULL, // no raw serialization handler
0 // don’t serialize
)

static
KSPROPERTY_STEPPING_LONG VolumeRangeAndStep =
{
{
0x0001, // SteppingDelta
0, // Reserved
0x8001, // Minimum
0x7FFF // Maximum
}
};

static
KSPROPERTY_MEMBERSLIST VolumeMembersList =
{
{
{
KSPROPERTY_MEMBER_RANGES,
sizeof (VolumeRangeAndStep),
SIZEOF_ARRAY (VolumeRangeAndStep),
0
},
(PVOID) VolumeRangeAndStep
},
};

static
KSPROPERTY_VALUES VolumeValues =
{
{
STATICGUIDOF (KSPROPTYPESETID_General),
VT_I4,
0
},
SIZEOF_ARRAY (VolumeMembersList),
VolumeMembersList
};

It’s interesting that you chose not to tell us what the actual values for vol_min, vol_max and vol_res >are. What I was trying to explore was the possibility that your range was actually inverted, and the >only way to check that is to know the actual numbers.
0x0001, // SteppingDelta
0x8001, // Minimum
0x7FFF // Maximum

Is “CCaptureFilter::ptr_CAVRequest” a global variable (or a class static)? That’s not a very good >design. What happens if you get several volume requests for multiple instances at the same time? >This would be easier to read if you made this a member function and had a static bridge, like

NTSTATUS SupportVolumeFunction( PIRP irp, PKSIDENTIFIER request, PVOID data )
> {
> PKSFILTER KsFilter = KsGetFilterFromIrp( irp );

CCaptureFilter* Filter = (CCaptureFilter*)GetFilterFromIrp(
KsFilter->Context );
return Filter->VolumeSupport( irp, request, data );
}

NTSTATUS CCaptureFilter::VolumeSupport( PIRP irp, PKSIDENTIFIER request, PVOID data )
{

}

thanks sir i will change it like that.

This property accepts a “long”, but you’re only fetching two bytes from the hardware. Since the >gain is often a signed value, you need to sign-extend the result. That’s probably your trouble. >Example:

short TempVolume;
CCaptureFilter::ptr_CAVRequest->req_params_obj.pdatabuffer = &TempVolume;
CCaptureFilter::ptr_CAVRequest->req_params_obj.length = 2;

CCaptureFilter::ptr_CAVRequest->InitiateAudioControlRequest( … );
// Sign-extend the short to a long.
*audvol = TempVolume.

i have done like that

short tempVol;
CCaptureFilter::ptr_CAVRequest->req_params_obj.pdatabuffer = &tempVol;
CCaptureFilter::ptr_CAVRequest->req_params_obj.length = 2;

CCaptureFilter::ptr_CAVRequest->InitiateAudioControlRequest( … );
*(PLONG)audvol = tempVol;

but the problem is same volume slider is again moving to the current value of volume.
in the KdPrint i am only getting the current value which i send from the device at the starting.
i am changing my slider and for set and get call the values are same whatever the current value.

xxxxx@lntinfotech.com wrote:

thanks Tim for your useful information
as you said to implement KSPROPERTY_VALUES

> Since you have a single stepped range, why did you write a support handler instead of just >providing a KSPROPERTY_VALUES structure and letting AVStream handle it for you?
>

static
KSPROPERTY_STEPPING_LONG VolumeRangeAndStep =
{
{
0x0001, // SteppingDelta
0, // Reserved
0x8001, // Minimum
0x7FFF // Maximum
}
};

static
KSPROPERTY_VALUES VolumeValues =
{
{
STATICGUIDOF (KSPROPTYPESETID_General),
VT_I4,
0
},
SIZEOF_ARRAY (VolumeMembersList),
VolumeMembersList
};

You simply are not thinking about your data types. The problem is
exactly as I stated before – you have an inversion. The data type of
this property is VT_I4 – it is a 32-bit signed value. Given that, your
minimum value is LARGER than your maximum value (by 2).

Here’s a hint. Set the minimum to 0xffff8001, or even better, -0x7fff.
I suspect that will solve your problem.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Tim Roberts wrote:

xxxxx@lntinfotech.com wrote:

> static
> KSPROPERTY_STEPPING_LONG VolumeRangeAndStep =
> {
> {
> 0x0001, // SteppingDelta
> 0, // Reserved
> 0x8001, // Minimum
> 0x7FFF // Maximum
> }
> };
> …
Here’s a hint. Set the minimum to 0xffff8001, or even better, -0x7fff.
I suspect that will solve your problem.

And, by the way, that value is supposed to be in units of 1/65536 dB.
So, your full volume range goes from -0.5 dB to +0.5 dB, which is not
very much of a range. You might consider scaling this value in your
property handler.

It’s true that most apps don’t treat this value literally as dB, but
they are certainly allowed to do so.


Tim Roberts, xxxxx@probo.com
Providenza & Boekelheide, Inc.

Thanks TIM

my problem got solved yes the problem was Data type.

i updated the max. and min. in the device side which i make it 4 bytes value and assign max & min value to driver in the supporthandler

max = 0x00007FFF
min = 0xFFFF8001

and in my get/set handler i updated the length to 4

CCaptureFilter::ptr_CAVRequest->req_params_obj.pdatabuffer=audvol;
CCaptureFilter::ptr_CAVRequest->req_params_obj.length=4;
CCaptureFilter::ptr_CAVRequest->req_params_obj.icontrol=VOLUME;

now i am fetching 4 bytes from the hardware.

so my volume control working properly.