内核dpc定时器
第一种方式是dpc定时器,这种方式是应用层主动拉流
KDPC channel0AudioDpc;
KTIMER channel0AudioTimer;
KeInitializeTimer(&devext->channel0AudioTimer); //初始化定时器对象
KeInitializeDpc( &devext->channel0AudioDpc, channel0AudioDpcRoutine, devext );//初始化dpc对象,注意最后一个参数就是channel0AudioDpcRoutine中的第二个参数。
NTSTATUS DispatchProcess (IN PKSPIN pin)
{
PDEVICE_EXTENSION devext = (PDEVICE_EXTENSION)(KsPinGetDevice(pin)->Context);
LARGE_INTEGER largetime;
largetime.QuadPart=-10 * 1000 *2; //number of 100 ns intervals ,so here is 2ms
KeSetTimer(&devext->channel0AudioTimer,largetime,&devext->channel0AudioDpc);
//开始DPC定时器,3个参数,第一个参数是KTIMER对象,第二个参数是时间间隔,第三个参数是dpc对象
return STATUS_PENDING;
}
//dpc 函数
void channel0AudioDpcRoutine(struct _KDPC* p_dpc,PVOID context,PVOID arg1,PVOID arg2)
eg: void OnDPCTimer(IN PKDPC pDPC,
IN PVOID pContext,//这就是KeInitializeDpc传入的参数
IN PVOID SysArg1,
IN PVOID SysArg2)
在需要停止的地方调用KeCancleTimer来取消定时器
第二种方式,中断函数中有中断到来时把它入队dpc,驱动往上推流
有中断时:KeInsertQueueDpc(&devext->channel0AudioDpc,NULL,NULL);
NTSTATUS DispatchProcess (IN PKSPIN pin)
{
return STATUS_PENDING; //此处直接返回,在dpc处理函数里向应用层写入。
}
第二种方法只能正确处理48K的声音:
总数据量:48000*2*2=192000,应用程序每次请求1920个字节,驱动中的CELL刚好也是1920,这样就每一个中断往应用层写入一次,每秒刚好有100个中断(192000/1920)。
这个时候两种方法的效果是一样的,第二种方法又不依赖系统的时钟分辨率(win10 64位中setTimer有15ms的误差)。所以处理48K的声音没有问题。
当源是44.1K时,44100*2*2=176400, 176400/1920=91.875
应用程序每次只请求1764个字节,每一个中断对应有1920个字节,这样每一个中断就会在驱动中累积156个字节而导致数据在驱动中溢出。解决这个问题只能更改驱动中的CELL刚好也是1764,但是它不是128的倍数又不满足fpga的要求。所以处理44.1K的声音是个问题。
第一种方法拉数据依赖应用程序的请求,不对应中断的个数去一对一的送数据就没这个限制。
另外,应用程序每次取声音的数据量是根据系统的声音设置而定的,系统声音设置“录制”属性中设置44100每次取1764,设置48000每次取1920。默认值是第一次安装驱动中的接口而定的。使用过程中如果信号源有改变,系统声音设置没办法同步更改,这样就会导致播放声音不正常。所以声音这一块驱动中要把44.1转为48最好,最好只有一种48K输出。