Как работать с CreateTimerQueueTimer
От: shenon  
Дата: 15.10.03 15:08
Оценка:
Пытаюсь освоить функцию CreateTimerQueueTimer. Замечательная функция, даёт достаточно жёсткую задержку, но непонятные глюки преследуют меня если я начинаю её использовать. Вот например, программа ввода вывода звука.
Вызов моей функции InitTimer() проводит к запуску таймера с периодичностью 10 милисекунд. В таймере забирается звук из звуковой карты с помощью и помещается в цикличекий буффер.
Microphone.Run();

Затем отдаётся на воспроизведение из этого буффера
Speaker.Run();

Глючность не зависит от производительности компьютера. Например на 150 Мгц ноутбуке Compaq Pressario замечательно работает. На настольном Celeron 350 похрюкивает, на других машинах 2 ГГЦ может поиграть 10 секунд и вообще зависнуть.
С помощью Soft-Ice нажимая cntr-D можно посмотреть, что в состоянии зависания всё время поподаешь в одно и то же место — какой то вечный цикл из 5 комманд.

Друзья, попробуйте вставьте в приложение Hellow World! InitTimer() и послушайте пошёл ли звук микрофона в динамик с небольшой задержкой. И не забудьте втавить winmm.lib . Помогите заставить работать без глюков, хрюков и зависаний замечательную функцию CreateTimerQueueTimer на любых компьютерах.

Вот файл QTIMER.CPP


#include "stdafx.h"
#include "devices.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


#define WT_EXECUTEDEFAULT       0x00000000                           
#define WT_EXECUTEINIOTHREAD    0x00000001                           
#define WT_EXECUTEINUITHREAD    0x00000002                           
#define WT_EXECUTEINWAITTHREAD  0x00000004                           
#define WT_EXECUTEONLYONCE      0x00000008                           
#define WT_EXECUTEINTIMERTHREAD 0x00000020                           
#define WT_EXECUTELONGFUNCTION  0x00000010                           
#define WT_EXECUTEINPERSISTENTIOTHREAD  0x00000040                   
#define WT_EXECUTEINPERSISTENTTHREAD 0x00000080  

typedef VOID (NTAPI * WAITORTIMERCALLBACK) (PVOID, BOOLEAN );   

typedef   WINBASEAPI HANDLE WINAPI
 pCreateTimerQueueFunc();
typedef WINBASEAPI BOOL WINAPI
 pCreateTimerQueueTimerFunc(
    PHANDLE phNewTimer,
    HANDLE TimerQueue,
    WAITORTIMERCALLBACK Callback,
    PVOID Parameter,
    DWORD DueTime,
    DWORD Period,
    ULONG Flags
);
pCreateTimerQueueFunc *CreateTimerQueueFunc;
pCreateTimerQueueTimerFunc *CreateTimerQueueTimerFunc;
HINSTANCE Lib;
HANDLE TimerQueue;
HANDLE m_timerHandle;



waveInDevice<short int> Microphone;
waveOutDevice<short int> Speaker;
SinGenerator<short int> SinGen;
  HANDLE hThread;
void CALLBACK TimerProc(void* lpParametar, BOOLEAN TimerOrWaitFired)
{ 
  static start=1;
  Microphone.Run();
  //SinGen.Run();
  if (start!=3)
  { 
    if (start==1)
        {    
         SetThreadPriority( GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL); 
         start=2;
         goto end;
         return;
        }
  
   if (start==2)
   { Speaker.Connect(&Microphone.Output);    
     //Speaker.Connect(&SinGen.Output);    
      start=3;
      goto end;
      return;
    }
  }
  else
  Speaker.Run();

end:
  ;
};

void InitTimer()
{ 
  Lib=LoadLibrary("kernel32.dll");
  CreateTimerQueueFunc=(pCreateTimerQueueFunc*)GetProcAddress(Lib,"CreateTimerQueue");
  TimerQueue=(*CreateTimerQueueFunc)();
  CreateTimerQueueTimerFunc=(pCreateTimerQueueTimerFunc*)GetProcAddress(Lib,"CreateTimerQueueTimer");
  
  BOOL success = (*CreateTimerQueueTimerFunc)(
        &m_timerHandle,
        TimerQueue,
        TimerProc,
        NULL,//this
        50,
        //1000,
        10, //10 msec - period
        WT_EXECUTEINTIMERTHREAD
        ); 

};


А вот файл devices.h . MSVC 5.0 может давть ошибку не везде стоит return. Но шестая студия глотает.



#ifndef devices_h
#define devices_h

class Device
{ virtual bool Run(){return true;};
};


template <class T>
struct CircBufOut
{ public:
  T * Start;
  T * End;
  T * Cursor;
};

template <class T>
class InputDevice :public Device
{ public:
  CircBufOut <T> Output;
};


template <class T>
class OutputDevice :public Device
{ public:
  virtual void Connect(CircBufOut <T> *input){};
};

template <class Tin, class Tout>
class InOutDevice : public InputDevice<Tin>  , public OutputDevice<Tout>
{
};


#include <windows.h>
#include <mmsystem.h>



template <class Tdata>
class
waveInDevice : public InputDevice <Tdata>
{
  private:
   CHAR outbuf[65536];

  HWAVEIN WaveInHnd;
  WAVEFORMATEX fmt;

  MMRESULT Res;
  DWORD EndPos;
  DWORD nblock;
  public:
  char ERR[200];
  waveInDevice()
  { UINT NumDev=waveInGetNumDevs();
     { fmt.wFormatTag=WAVE_FORMAT_PCM;
       fmt.nChannels=1;
       fmt.nSamplesPerSec=8000;
       fmt.nAvgBytesPerSec=sizeof(Tdata)*8000;
       fmt.nBlockAlign=2;
       fmt.wBitsPerSample=sizeof(Tdata)*8;
       fmt.cbSize=0;

       Res=waveInOpen(&WaveInHnd,
                  WAVE_MAPPER,
                            &fmt,
                               0,
                   CALLBACK_NULL,
                                0
                               );
       if (Res==0)
         {
          Output.Start=(Tdata*)outbuf;
          Output.Cursor=Output.Start;
          Output.End=(Tdata*)(outbuf+65536);
          EndPos=0;
          nblock=0;

          waveInStart(WaveInHnd);

         }
       else
         { waveInGetErrorText(Res,ERR,200);
         }
     }
  };

 ~waveInDevice()
 { if (WaveInHnd!=NULL)
   waveInClose(WaveInHnd);
 }

  WAVEHDR hdr[4];  
  bool Run()
  { MMTIME mmt;
    mmt.wType=TIME_BYTES;
    MMRESULT result=waveInGetPosition(WaveInHnd,&mmt,sizeof(mmt));
    DWORD pos=mmt.u.cb;
    Output.Cursor=(Tdata*)((DWORD)Output.Start+(DWORD)(pos & 0xFFFF));
    if ((EndPos-pos)<16384)
    { MMRESULT R;
      LPSTR pdata=outbuf+nblock*16384;
      
      hdr[nblock].lpData=pdata;
      hdr[nblock].dwBufferLength=16384;
      hdr[nblock].dwBytesRecorded=0;
      hdr[nblock].dwUser=0;
      hdr[nblock].dwFlags=0;
      hdr[nblock].dwLoops=0;
      hdr[nblock].lpNext=0;
      hdr[nblock].reserved=0;
      R=waveInPrepareHeader(WaveInHnd,&hdr[nblock],sizeof(WAVEHDR) );
      R=waveInAddBuffer(WaveInHnd,&hdr[nblock], sizeof(WAVEHDR) );
      nblock++;
      EndPos+=16384;
      if (nblock>=4) nblock-=4;
    }

    return Res;//get Res from waveInOpen
  };

};





extern UINT WaveOutBuzyNumDev;


template <class Tdata>
class waveOutDevice : public OutputDevice < Tdata >
{
  private:

  HWAVEOUT WaveOutHnd;
  WAVEFORMATEX fmt;

  MMRESULT Res;
  CircBufOut <Tdata> * Input;
  CircBufOut <Tdata> LastInput;


  public:
  char ERR[200];
  char buf[65536];
  waveOutDevice()
  { UINT NumDev=waveOutGetNumDevs();
     { fmt.wFormatTag=WAVE_FORMAT_PCM;
       fmt.nChannels=1;
       fmt.nSamplesPerSec=8000;
       fmt.nAvgBytesPerSec=sizeof(Tdata)*8000;
       fmt.nBlockAlign=sizeof(Tdata);
       fmt.wBitsPerSample=sizeof(Tdata)*8;
       fmt.cbSize=0;
       Res=waveOutOpen(&WaveOutHnd,
                     WAVE_MAPPER,
                            &fmt,
                               0,
                               0,
                               0
                               );
       if (Res==0)
         {Input=NULL;
          nh=0;
         }
       else
         { waveInGetErrorText(Res,ERR,200);
         }
     }
  };

 ~waveOutDevice()
 { if (WaveOutHnd!=NULL)
   {waveOutClose(WaveOutHnd);
   }
 }

 void Connect(CircBufOut <Tdata> * pd)
  { Input=pd;
    LastInput=*Input;
//    waveOutReset(WaveOutHnd);
  };
 WAVEHDR hdr[20];
 int nh;
 bool Run()
  {   int nd;
 
      Tdata *NP;
      NP=Input->Cursor;
      MMRESULT R;
      if (NP>LastInput.Cursor)
      {
        hdr[nh].lpData=(LPSTR)LastInput.Cursor;
        hdr[nh].dwBufferLength=((DWORD)NP-(DWORD)LastInput.Cursor);
        hdr[nh].dwBytesRecorded=0;
        hdr[nh].dwUser=0;
        hdr[nh].dwFlags=0;
        hdr[nh].dwLoops=0;
        hdr[nh].lpNext=0;
        hdr[nh].reserved=0;
        R=waveOutPrepareHeader(WaveOutHnd,&hdr[nh],sizeof(WAVEHDR));
        waveOutWrite(WaveOutHnd,&hdr[nh], sizeof(WAVEHDR) );
        LastInput.Cursor=NP;
        nh++;
        if (nh>=20) nh-=20;
        return true;
      }

      if (NP<LastInput.Cursor)
      { // waveOutReset(WaveOutHnd);
        memcpy(buf,NP,(Input->End-NP));
        memcpy(buf+(Input->End-NP),Input->Start,(NP-Input->Start));

        hdr[nh].lpData=(LPSTR)buf;
        hdr[nh].dwBufferLength=((DWORD)LastInput.End-(DWORD)LastInput.Cursor)+
                               ((DWORD)NP-(DWORD)LastInput.Start);
        hdr[nh].dwBytesRecorded=0;
        hdr[nh].dwUser=0;
        hdr[nh].dwFlags=0;
        hdr[nh].dwLoops=0;
        hdr[nh].lpNext=0;
        hdr[nh].reserved=0;

        R=waveOutPrepareHeader(WaveOutHnd,&hdr[nh],sizeof(WAVEHDR));
        waveOutWrite(WaveOutHnd,&hdr[nh], sizeof(WAVEHDR) );
        nh++;
        if (nh>=20) nh-=20;
        LastInput.Cursor=NP;
        return true;
      }
  };

};

#include <math.h>
#define M_PI (3.141592653589793238462)
template <class Tdata>
class SinGenerator : public InputDevice < Tdata >
{ Tdata outbuf[64000];
   int step;
  public:
   SinGenerator()
    { int i;
      for(i=0;i<64000;i++)
      { if (sizeof(Tdata)==2)
        { outbuf[i]=32767.*sin(2*M_PI*i*1000./8000.0);//1000 Hz
        }
      }
       step=1;
    Output.Start=outbuf;
    Output.End=outbuf+64000;
    Output.Cursor=outbuf;
    }

   bool Run()
   { Output.Cursor+=1000;   //0.125 sec = 1000/8000
     if (Output.Cursor>=Output.End)
       Output.Cursor-=64000;
     return true;
   }

};



#endif
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.