> 文章列表 > 内核dpc定时器

内核dpc定时器

内核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输出。