NetAudio.pas
上传用户:axbxcx
上传日期:2009-10-29
资源大小:15k
文件大小:17k
源码类别:

TAPI编程

开发平台:

Delphi

  1. unit NetAudio;
  2. interface
  3. uses Windows, Messages, SysUtils, Variants, Classes, MMSystem, DblPxyTcp,
  4.      blcksock, synsock;
  5. const
  6.   WM_STATEMESSAGE  = WM_USER + 101;
  7.   WM_CLIENTCONNECT = WM_USER + 102;
  8.   WM_CONNECTED     = WM_USER + 103;
  9.   WM_SENDAUDIO     = WM_USER + 121;
  10.   WM_RECVAUDIO     = WM_USER + 122;
  11.   WM_TERMINATE     = WM_USER + 123;
  12.   mtListenStart = 1;
  13.   mtListening   = 2;
  14.   mtListenFail  = 3;
  15.   mtListenClose = 4;
  16.   mtConnecting  = 5;
  17.   mtConnectFail = 6;
  18.   mtRecvFail    = 7;
  19.   mtRecvClose   = 8;
  20.   mtSendClose   = 9;
  21.   mtRefused     = 10;
  22.   mtInvConnect  = 11;
  23.   mtMustSelIP   = 12;
  24.   mtPeerBusy    = 13;
  25.   mtSendFail    = 14;
  26.   MAXDELAYTIME   = 50;
  27.     
  28. type
  29.   TIniTaskFlag = (tfDoNothing, tfDoConnect, tfDoRefuse, tfDoBusy, tfDoAgree);
  30.   TAudioListenThread = class(TThread)
  31.   protected
  32.     FSocket: TDblProxyTcpSocket;
  33.     FWindow: HWND;
  34.     FIPIndex: Integer;
  35.     FPort: string;
  36.   public
  37.     constructor Create(hwin: HWND; const port: string);
  38.     destructor Destroy; override;
  39.     procedure Execute; override;
  40.     property Socket: TDblProxyTcpSocket read FSocket;
  41.     property IPIndex: Integer read FIPIndex write FIPIndex;
  42.   end;
  43.   TAudioBaseThread = class(TThread)
  44.   protected
  45.     FSocket: TDblProxyTcpSocket;
  46.     FTask: TIniTaskFlag;
  47.     FWindow: HWND;
  48.     FHost, FPort: string;
  49.   public
  50.     constructor Create(hwin: HWND; sock: TDblProxyTcpSocket; task: TIniTaskFlag);
  51.     function DoIniTask: Boolean;
  52.     property Socket: TDblProxyTcpSocket read FSocket;
  53.     property Host: string read FHost write FHost;
  54.     property Port: string read FPort write FPort;
  55.   end;
  56.   TAudioRecvThread = class(TAudioBaseThread)
  57.   protected
  58.     FSpeakerOpen: Boolean;
  59.   public
  60.     constructor Create(hwin: HWND; sock: TDblProxyTcpSocket; task: TIniTaskFlag);
  61.     procedure Execute; override;
  62.     property SpeakerOpen: Boolean read FSpeakerOpen write FSpeakerOpen;
  63.     property Socket;
  64.     property Host;
  65.     property Port;
  66.   end;
  67.   TAudioSendThread = class(TAudioBaseThread)
  68.   protected
  69.     FPhoneOpen: Boolean;
  70.   public
  71.     constructor Create(hwin: HWND; sock: TDblProxyTcpSocket; task: TIniTaskFlag);
  72.     procedure Execute; override;
  73.     property PhoneOpen: Boolean read FPhoneOpen write FPhoneOpen;
  74.     property Socket;
  75.     property Host;
  76.     property Port;
  77.   end;
  78.   function AudioInOpened: Boolean;
  79.   function OpenAudioIn(thread: Cardinal): Integer;
  80.   function SetThreadIn(thread: Cardinal): Cardinal;
  81.   procedure CloseAudioIn;
  82.   procedure StartAudioIn;
  83.   function AudioOutOpened: Boolean;
  84.   function OpenAudioOut(thread: Cardinal): Integer;
  85.   function SetThreadOut(thread: Cardinal): Cardinal;
  86.   procedure CloseAudioOut;
  87.   procedure StartAudioOut;
  88.   function SetDelayTime(n: Integer): Integer;
  89. implementation
  90. const
  91.   WAVINBUFCOUNT  = 3;
  92.   WAVOUTBUFCOUNT = 3;
  93.   WAVMAXBUFSIZE  = 13000;
  94. type
  95.   TPCMWaveFormat = packed record
  96.     Wav: TWAVEFORMATEX;
  97.     Gsm: Word;
  98.   end;
  99.   PPCMWaveFormat = ^TPCMWaveFormat;
  100. var AudioInOpen, AudioOutOpen: Boolean;
  101.     DevAudioIn: HWAVEIN;
  102.     DevAudioOut: HWAVEOUT;
  103.     WavInFmt, WavOutFmt: TPCMWaveFormat;
  104.     WavInHdr: array [0..WAVINBUFCOUNT-1] of WAVEHDR;
  105.     WavOutHdr: array [0..WAVOUTBUFCOUNT-1] of WAVEHDR;
  106.     BufInSize: Integer;
  107.     ThreadIn, ThreadOut: Cardinal;
  108.     DelayTime: Integer;
  109.     WavInBuf, WavOutBuf: PByteArray;
  110. constructor TAudioListenThread.Create(hwin: HWND; const port: string);
  111. begin
  112.   inherited Create(True);
  113.   FWindow := hwin;
  114.   FPort := port;
  115.   FIPIndex := 0;
  116.   FSocket := TDblProxyTcpSocket.Create;
  117.   FreeOnTerminate := True;
  118. end;
  119. destructor TAudioListenThread.Destroy;
  120. begin
  121.   FSocket.Free;
  122.   inherited Destroy;
  123. end;
  124. procedure TAudioListenThread.Execute;
  125. var s: TSocket;
  126.     a: string;
  127.     b: TStringList;
  128. begin
  129.   PostMessage(FWindow, WM_STATEMESSAGE, mtListenStart, 0);
  130.   b := TStringList.Create;
  131.   FSocket.ResolveNameToIP(FSocket.LocalName, b);
  132.   if (b.Count > 0) and (FSocket.SocksIP = '') then
  133.   begin
  134.     FIPIndex := -2;
  135.     PostMessage(FWindow, WM_STATEMESSAGE, mtMustSelIP, Integer(b));
  136.     while FIPIndex < -1 do Sleep(100);
  137.   end
  138.   else FIPIndex := 0;
  139.   if FIPIndex < 0 then
  140.   begin
  141.     PostMessage(FWindow, WM_STATEMESSAGE, mtListenClose, 0);
  142.     Exit;
  143.   end
  144.   else if FIPIndex < b.Count then a := b.Strings[FIPIndex]
  145.   else a := cAnyHost;
  146.   b.Free;
  147.   FSocket.Bind(a, FPort);
  148.   FSocket.Listen;
  149.   if FSocket.LastError <> 0 then
  150.   begin
  151.     PostMessage(FWindow, WM_STATEMESSAGE, mtListenFail, 0);
  152.     Exit;
  153.   end;
  154.   FSocket.GetSins;
  155.   PostMessage(FWindow, WM_STATEMESSAGE, mtListening, 0);
  156.   while not Terminated do
  157.   begin
  158.     if FSocket.CanRead(500) then
  159.     begin
  160.       s := FSocket.Accept;
  161.       if FSocket.LastError = 0 then
  162.       begin
  163.         PostMessage(FWindow, WM_CLIENTCONNECT, s, 0);
  164.         if FSocket.UsingSocks then
  165.         begin
  166.           FSocket.Socket := INVALID_SOCKET;
  167.           FSocket.Bind(a, FPort);
  168.           FSocket.Listen;
  169.           if FSocket.LastError <> 0 then
  170.           begin
  171.             PostMessage(FWindow, WM_STATEMESSAGE, mtListenFail, 0);
  172.             Exit;
  173.           end;
  174.           FSocket.GetSins;
  175.           PostMessage(FWindow, WM_STATEMESSAGE, mtListening, 0);
  176.         end;
  177.       end;
  178.     end;
  179.   end;
  180.   PostMessage(FWindow, WM_STATEMESSAGE, mtListenClose, 0);
  181. end;
  182. constructor TAudioBaseThread.Create(hwin: HWND; sock: TDblProxyTcpSocket; task: TIniTaskFlag);
  183. begin
  184.   inherited Create(True);
  185.   FSocket := sock;
  186.   FWindow := hwin;
  187.   FTask := task;
  188.   FHost := '';
  189.   FPort := '';
  190.   FreeOnTerminate := True;
  191. end;
  192. function TAudioBaseThread.DoIniTask: Boolean;
  193. const ptPhoneRequest = $6C;
  194.       ptPhoneAccept  = $6A;
  195.       ptPhoneCanRec  = $A6;
  196.       ptPhoneRefuse  = $00;
  197.       ptPhoneBusy    = $01;
  198.       ptPhoneRecord  = $02;
  199. var b: Byte;
  200. begin
  201.   FSocket.SetTimeout(1000);
  202.   case FTask of
  203.     tfDoConnect:
  204.     begin
  205.       PostMessage(FWindow, WM_STATEMESSAGE, mtConnecting, 0);
  206.       FSocket.Connect(FHost, FPort);
  207.       if FSocket.LastError <> 0 then
  208.       begin
  209.         PostMessage(FWindow, WM_STATEMESSAGE, mtConnectFail, 0);
  210.         Result := False;
  211.       end
  212.       else begin
  213.         FSocket.SendByte(ptPhoneRequest);
  214.         repeat  // 等待直到对方发送确认信息或者退出
  215.           b := FSocket.RecvByte(1000);
  216.           if FSocket.LastError = 0 then
  217.           begin
  218.             if b = ptPhoneAccept then
  219.             begin
  220.               PostMessage(FWindow, WM_CONNECTED, 0, 0);
  221.               Result := True;
  222.               Exit;
  223.             end
  224.             else if b = ptPhoneBusy then
  225.             begin
  226.               PostMessage(FWindow, WM_STATEMESSAGE, mtPeerBusy, 0);
  227.               Result := False;
  228.               Exit;
  229.             end
  230.             else begin
  231.               PostMessage(FWindow, WM_STATEMESSAGE, mtRefused, 0);
  232.               Result := False;
  233.               Exit;
  234.             end;
  235.           end
  236.           else if FSocket.LastError <> WSAETIMEDOUT then
  237.           begin
  238.             PostMessage(FWindow, WM_STATEMESSAGE, mtRecvFail, 0);
  239.             Result := False;
  240.             Exit;
  241.           end;
  242.         until Terminated;
  243.         PostMessage(FWindow, WM_STATEMESSAGE, mtRecvClose, 0);
  244.         Result := False;
  245.       end;
  246.     end;
  247.     tfDoRefuse:
  248.     begin
  249.        FSocket.SendByte(ptPhoneRefuse);
  250.        Sleep(1000);
  251.        FSocket.Free;
  252.        Result := False;
  253.     end;
  254.     tfDoBusy:
  255.     begin
  256.        FSocket.SendByte(ptPhoneBusy);
  257.        Sleep(1000);
  258.        FSocket.Free;
  259.        Result := False;
  260.     end;
  261.     tfDoAgree:
  262.     begin
  263.       if FSocket.RecvByte(5000) <> ptPhoneRequest then
  264.       begin
  265.         PostMessage(FWindow, WM_STATEMESSAGE, mtInvConnect, 0);
  266.         Result := False;
  267.         Exit;
  268.       end;
  269.       FSocket.SendByte(ptPhoneAccept);
  270.       PostMessage(FWindow, WM_CONNECTED, 0, 0);
  271.       Result := True;
  272.     end;
  273.     else Result := True;
  274.   end;
  275. end;
  276. constructor TAudioRecvThread.Create(hwin: HWND; sock: TDblProxyTcpSocket; task: TIniTaskFlag);
  277. begin
  278.   inherited Create(hwin, sock, task);
  279.   FSpeakerOpen := True;
  280. end;
  281. procedure TAudioRecvThread.Execute;
  282. const RECVTIMEOUT = 2000;
  283. var i, j, n: Integer;
  284.     buf: array[0..Sizeof(Integer)-1] of Byte absolute n;
  285.     p: PWAVEHDR;
  286.     ms: MSG;
  287. begin
  288.   if not DoIniTask then Exit;
  289.   while not Terminated do
  290.   begin
  291.     GetMessage(ms, 0, 0, 0);
  292.     case ms.message of
  293.       WM_RECVAUDIO:
  294.       begin
  295.         i := 0;
  296.         repeat
  297.           i := i + FSocket.RecvBufferEx(@buf[i], Sizeof(Integer) - i, RECVTIMEOUT);
  298.           if (i >= Sizeof(Integer)) and (FSocket.LastError = 0) then
  299.           begin
  300.             if n > WAVMAXBUFSIZE then
  301.             begin
  302.               PostMessage(FWindow, WM_STATEMESSAGE, mtRecvFail, 0);
  303.               Exit;
  304.             end;
  305.             j := 0;
  306.             repeat
  307.               p := PWAVEHDR(ms.lParam);
  308.               j := j + FSocket.RecvBufferEx(@(p^.lpData[j]), n - j, RECVTIMEOUT);
  309.               if (j >= n) and (FSocket.LastError = 0) then
  310.               begin
  311.                 if FSpeakerOpen then
  312.                 begin
  313.                   p^.dwFlags := 0;
  314.                   p^.dwBufferLength := n;
  315.                   p^.dwBytesRecorded := n;
  316.                   waveOutPrepareHeader(ms.wParam, p, Sizeof(WAVEHDR));
  317.                   waveOutWrite(ms.wParam, p, Sizeof(WAVEHDR));
  318.                 end
  319.                 else
  320.                   PostThreadMessage(ThreadID, WM_RECVAUDIO, ms.wParam, ms.lParam);
  321.               end
  322.               else if (FSocket.LastError <> 0) and (FSocket.LastError <> WSAETIMEDOUT) then
  323.               begin
  324.                 PostMessage(FWindow, WM_STATEMESSAGE, mtRecvFail, 0);
  325.                 Exit;
  326.               end;
  327.             until (j >= n) or Terminated;
  328.           end
  329.           else if (FSocket.LastError <> 0) and (FSocket.LastError <> WSAETIMEDOUT) then
  330.           begin
  331.             PostMessage(FWindow, WM_STATEMESSAGE, mtRecvFail, 0);
  332.             Exit;
  333.           end;
  334.         until (i >= Sizeof(Integer)) or Terminated;
  335.       end;
  336.       WM_TERMINATE: Terminate;
  337.     end; // case
  338.   end; // while
  339.   PostMessage(FWindow, WM_STATEMESSAGE, mtRecvClose, 0);
  340. end;
  341. constructor TAudioSendThread.Create(hwin: HWND; sock: TDblProxyTcpSocket; task: TIniTaskFlag);
  342. begin
  343.   inherited Create(hwin, sock, task);
  344.   FPhoneOpen := True;
  345. end;
  346. procedure TAudioSendThread.Execute;
  347. var i, j, m, n: Integer;
  348.     buf: array[0..Sizeof(Integer)-1] of Byte absolute n;
  349.     p: PWAVEHDR;
  350.     ms: MSG;
  351. begin
  352.   if not DoIniTask then Exit;
  353.   m := 0;
  354.   while not Terminated do
  355.   begin
  356.     GetMessage(ms, 0, 0, 0);
  357.     case ms.message of
  358.       WM_SENDAUDIO:
  359.       begin
  360.         p := PWAVEHDR(ms.lParam);
  361.         n := p^.dwBytesRecorded;
  362.         if FPhoneOpen and (n >= m) then
  363.         begin
  364.           i := 0;
  365.           repeat
  366.             i := i + FSocket.SendBuffer(@buf[i], Sizeof(Integer) - i);
  367.             if (i >= Sizeof(Integer)) and (FSocket.LastError = 0) then
  368.             begin
  369.               j := 0;
  370.               repeat
  371.                 j := j + FSocket.SendBuffer(@(p^.lpData[j]), n - j);
  372.                 if FSocket.LastError <> 0 then
  373.                 begin
  374.                   PostMessage(FWindow, WM_STATEMESSAGE, mtSendFail, 0);
  375.                   Exit;
  376.                 end;
  377.               until (j >= n) or Terminated;
  378.               if Terminated then
  379.               begin
  380.                 PostMessage(FWindow, WM_STATEMESSAGE, mtSendClose, 0);
  381.                 Exit;
  382.               end;
  383.               m := n;
  384.             end
  385.             else if FSocket.LastError <> 0 then
  386.             begin
  387.               PostMessage(FWindow, WM_STATEMESSAGE, mtSendFail, 0);
  388.               Exit;
  389.             end;
  390.           until (i >= Sizeof(Integer)) or Terminated;
  391.         end;
  392.         if m > n then Dec(m, n);
  393.         p^.dwFlags := 0;
  394.         p^.dwBytesRecorded := 0;
  395.         p^.dwBufferLength := BufInSize;
  396.         waveInPrepareHeader(ms.wParam, p, Sizeof(WAVEHDR));
  397.         waveInAddBuffer(ms.wParam, p, Sizeof(WAVEHDR));
  398.       end;
  399.       WM_TERMINATE: Terminate;
  400.     end; // case
  401.   end; // while
  402.   PostMessage(FWindow, WM_STATEMESSAGE, mtSendClose, 0);
  403. end;
  404. procedure InitAudioVars;
  405. begin
  406.   with WavInFmt do
  407.   begin
  408.     Wav.wFormatTag := 49; // GSM 6.10 语音格式,11025Hz8位单声道;
  409.     Wav.nChannels := 1;
  410.     Wav.nSamplesPerSec := 11025;
  411.     Wav.nAvgBytesPerSec := 2239;
  412.     Wav.nBlockAlign := 65;
  413.     Wav.wBitsPerSample := 0;
  414.     Wav.cbSize := 2;
  415.     Gsm := 320;
  416.   end;
  417.   WavOutFmt := WavInFmt;
  418.   AudioInOpen := False;
  419.   AudioOutOpen := False;
  420.   DevAudioIn := 0;
  421.   DevAudioOut := 0;
  422.   BufInSize := 780;
  423.   DelayTime := 3;
  424.   ThreadIn := 0;
  425.   ThreadOut := 0;
  426.   WavInBuf := nil;
  427.   WavOutBuf := nil;
  428. end;
  429. procedure WaveInProc(hw: HWAVEIN; ms: Integer; ux: Cardinal; p1: PWAVEHDR; p2: Cardinal); stdcall; far;
  430. begin
  431.   if ms = WIM_DATA then
  432.   begin
  433.     waveInUnprepareHeader(hw, p1, Sizeof(WAVEHDR));
  434.     if ThreadIn <> 0 then PostThreadMessage(ThreadIn, WM_SENDAUDIO, hw, Integer(p1));
  435.   end;
  436. end;
  437. function AudioInOpened: Boolean;
  438. begin
  439.   Result := AudioInOpen;
  440. end;
  441. function OpenAudioIn(thread: Cardinal): Integer;
  442. var i: Integer;
  443. begin
  444.   if AudioInOpen then CloseAudioIn;
  445.   ThreadIn := thread;
  446.   Result := waveInOpen(@DevAudioIn, WAVE_MAPPER, @WavInFmt, Cardinal(@WaveInProc), 0, CALLBACK_FUNCTION);
  447.   AudioInOpen := Result = MMSYSERR_NOERROR;
  448.   if not AudioInOpen then Exit;
  449.   GetMem(WavInBuf, WAVMAXBUFSIZE * WAVINBUFCOUNT);
  450.   for i := 0 to WAVINBUFCOUNT - 1 do
  451.   begin
  452.     WavInHdr[i].lpData := @(WavInBuf^[i*WAVMAXBUFSIZE]);
  453.     WavInHdr[i].dwBufferLength := BufInSize;
  454.     WavInHdr[i].dwBytesRecorded := 0;
  455.     WavInHdr[i].dwFlags := 0;
  456.     Result := waveInPrepareHeader(DevAudioIn, @WavInHdr[i], Sizeof(WAVEHDR));
  457.     AudioInOpen := Result = MMSYSERR_NOERROR;
  458.     if not AudioInOpen then
  459.     begin
  460.       waveInClose(DevAudioIn);
  461.       FreeMem(WavInBuf, WAVMAXBUFSIZE * WAVINBUFCOUNT);
  462.       WavInBuf := nil;
  463.       Exit;
  464.     end;
  465.     Result := waveInAddBuffer(DevAudioIn, @WavInHdr[i], Sizeof(WAVEHDR));
  466.     AudioInOpen := Result = MMSYSERR_NOERROR;
  467.     if not AudioInOpen then
  468.     begin
  469.       waveInClose(DevAudioIn);
  470.       FreeMem(WavInBuf, WAVMAXBUFSIZE * WAVINBUFCOUNT);
  471.       WavInBuf := nil;
  472.       Exit;
  473.     end;
  474.   end;
  475. end;
  476. function SetThreadIn(thread: Cardinal): Cardinal;
  477. begin
  478.   Result := ThreadIn;
  479.   ThreadIn := thread;
  480. end;
  481. procedure CloseAudioIn;
  482. begin
  483.   if AudioInOpen then
  484.   begin
  485.     ThreadIn := 0;
  486.     waveInStop(DevAudioIn);
  487.     waveInReset(DevAudioIn);
  488.     waveInClose(DevAudioIn);
  489.     FreeMem(WavInBuf, WAVMAXBUFSIZE * WAVINBUFCOUNT);
  490.     WavInBuf := nil;
  491.     AudioInOpen := False;
  492.   end;
  493. end;
  494. procedure StartAudioIn;
  495. begin
  496.   if AudioInOpen then waveInStart(DevAudioIn);
  497. end;
  498. procedure WaveOutProc(hw: HWAVEOUT; ms: Integer; ux: Cardinal; p1: PWAVEHDR; p2: Cardinal); stdcall; far;
  499. begin
  500.   if ms = WOM_DONE then
  501.   begin
  502.     waveOutUnprepareHeader(hw, p1, Sizeof(WAVEHDR));
  503.     if ThreadOut <> 0 then PostThreadMessage(ThreadOut, WM_RECVAUDIO, hw, Integer(p1));
  504.   end;  
  505. end;
  506. function AudioOutOpened: Boolean;
  507. begin
  508.   Result := AudioOutOpen;
  509. end;
  510. function OpenAudioOut(thread: Cardinal): Integer;
  511. begin
  512.   if AudioOutOpen then CloseAudioOut;
  513.   ThreadOut := thread;
  514.   GetMem(WavOutBuf, WAVMAXBUFSIZE * WAVOUTBUFCOUNT);
  515.   Result := waveOutOpen(@DevAudioOut, WAVE_MAPPER, @WavOutFmt, Cardinal(@WaveOutProc), 0, CALLBACK_FUNCTION);
  516.   AudioOutOpen := Result = MMSYSERR_NOERROR;
  517.   if not AudioOutOpen then
  518.   begin
  519.     FreeMem(WavOutBuf, WAVMAXBUFSIZE * WAVOUTBUFCOUNT);
  520.     WavOutBuf := nil;
  521.   end;
  522. end;
  523. function SetThreadOut(thread: Cardinal): Cardinal;
  524. begin
  525.   Result := ThreadOut;
  526.   ThreadOut := thread;
  527. end;
  528. procedure CloseAudioOut;
  529. begin
  530.   if AudioOutOpen then
  531.   begin
  532.     ThreadOut := 0;
  533.     waveOutReset(DevAudioOut);
  534.     waveOutClose(DevAudioOut);
  535.     FreeMem(WavOutBuf, WAVMAXBUFSIZE * WAVOUTBUFCOUNT);
  536.     WavOutBuf := nil;
  537.     AudioOutOpen := False;
  538.   end;
  539. end;
  540. procedure StartAudioOut;
  541. var i: Integer;
  542. begin
  543.   if AudioOutOpen and (ThreadOut <> 0) then for i := 0 to WAVOUTBUFCOUNT - 1 do
  544.   begin
  545.     WavOutHdr[i].lpData := @(WavOutBuf^[i*WAVMAXBUFSIZE]);
  546.     WavOutHdr[i].dwBufferLength := BufInSize;
  547.     WavOutHdr[i].dwBytesRecorded := 0;
  548.     WavOutHdr[i].dwFlags := 0;
  549.     WavOutHdr[i].dwLoops := 1;
  550.     PostThreadMessage(ThreadOut, WM_RECVAUDIO, DevAudioOut, Integer(@WavOutHdr[i]));
  551.   end;
  552. end;
  553. function SetDelayTime(n: Integer): Integer;
  554. begin
  555.   Result := DelayTime;
  556.   if n < 1 then n := 1 else if n > MAXDELAYTIME then n := MAXDELAYTIME;
  557.   if n <> DelayTime then
  558.   begin
  559.     DelayTime := n;
  560.     n := Round(0.5 + 223.9 * n / 65);
  561.     BufInSize := n * 65;
  562.   end;
  563. end;
  564. begin
  565.   InitAudioVars;
  566. end.