⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unaconfserver.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 3 页
字号:

(*
	----------------------------------------------

	  unaConfServer.pas - ConfServer class
	  Voice Communicator components version 2.5

	----------------------------------------------
	  This source code cannot be used without
	  proper license granted to you as a private
	  person or an entity by the Lake of Soft, Ltd

	  Visit http://lakeofsoft.com/ for more information.

	  Copyright (c) 2001, 2007 Lake of Soft, Ltd
		     All rights reserved
	----------------------------------------------

	  created by:
		Lake, 08 Jul 2003

	  modified by:
		Lake, Jul, Dec 2003
		Lake, Jan, Feb 2004
		Lake, May-Oct 2005
		Lake, Mar-Jun 2006
		Lake, Apr 2007

	----------------------------------------------

*)

{$I unaDef.inc }

{*** $DEFINE USE_INSTALLABLE_DRIVERS }	// define to force codecs to use installable drivers rather than default ACM drivers

{$IFDEF DEBUG }
  {xx $DEFINE CS_LOG_MAX }		// enable extensive logging
  {xx $DEFINE DEBUG_NASTY_EXCEPTION }	// enable exceptions additional info log
  {xx $DEFINE DEBUG_EXTRA_DELAY } 	// include additional random delay in send thread for debugging
  {xx $DEFINE DEBUG_DUMMY_CODEC }	// use dummy installable driver for debugging
{$ENDIF }

unit
  unaConfServer;

interface

uses
  Windows, unaTypes, unaUtils, unaClasses, unaMsAcmClasses, unaVcIDE;

var
  c_maxClients: uint = 15;

const
  c_maxClientsLimit	= 100;

  c_defSamplingRate	= 8000;
  c_defBitsPerSample	= 16;
  c_defNumChannels	= 1;


  c_ticksPerSecond	= 10;


  c_outFormatTag	= 49;	// GSM - this codec will be used by default to compress
				// audio sent back to clients

  // -- error codec --
  c_unaconfserr_unknownDriver	= 1;
  c_unaconfserr_driverNotFound	= 2;
  c_unaconfserr_driverFound	= 3;

type
  // ahead declaration
  unaConfServerClass = class;

  //
  // -- some overrides --
  //
  unaConfIPServer = class(TunavclIPInStream)
  private
    f_master: unaConfServerClass;
  protected
    function onNewPacket(const packet: unavclInOutIPPacket; connId: unsigned): bool; override;
    procedure doAcceptClient(connId: unsigned; var accept: bool); override;
    procedure doServerClientConnection(connId: unsigned; isConnected: bool); override;
  public
    constructor createServer(master: unaConfServerClass);
  end;


  //
  // -- unaConfServerClient --
  //
  unaConfServerClient = record
    //
    r_connId: unsigned;
    r_codecIn: TunavclWaveCodecDevice;
    r_codecOut: TunavclWaveCodecDevice;
    r_mixerStream: unaAbstractStream;
  end;

  //
  //
  tunaConfError = procedure(sender: tObject; errorCode, errorInfo: int) of object;


  //
  // -- unaCSSendThreadRecord --
  //
  punaCSSendThreadRecord = ^unaCSSendThreadRecord;
  unaCSSendThreadRecord = packed record
    //
    r_connId: uint;
    r_cmdu: uint;
    r_data: pointer;
    r_lenu: uint;
  end;


  //
  // -- unaCSSendThread --
  //
  unaCSSendThread = class(unaThread)
  private
    f_sentOK: array[0..c_maxClientsLimit - 1] of int64;
    f_records: unaRecordList;
    f_master: unaConfServerClass;
    f_sentFail: array[0..c_maxClientsLimit - 1] of int64;
  protected
    function execute(threadId: uint): int; override;
  public
    constructor create(master: unaConfServerClass);
    procedure AfterConstruction(); override;
    procedure BeforeDestruction(); override;
    //
    function addSendRecord(connId: uint; cmd: uint; data: pointer; len: uint): bool;
  end;


  //
  // -- unaConfServerClass --
  //
  unaConfServerClass = class(unaMMTimer)
  private
    f_mixBuf: pArray;
    f_mixBufSize: unsigned;
    f_bcMixed: int64;
    //
    f_bytesSent: int64;
    f_bytesReceived: int64;
    //
    f_samplingRate: int;
    f_bitsPerSample: int;
    f_numChannels: int;
    f_outFormatTag: int;
    //
    f_ipServer: unaConfIPServer;
    f_mixer: unaWaveMultiStreamDevice;
    f_senderThread: unaCSSendThread;
    //
    f_clients: array[0..c_maxClientsLimit - 1] of unaConfServerClient;
    f_clientLock: unaInProcessGate;
    f_clientCount: unsigned;
    //
    f_onAC: tunavclAcceptClient;
    f_onCE: tunavclConnectEvent;
    f_onError: tunaConfError;
    //
    f_lastTimerTick: int64;
    //
    function getClientIndex(connId: unsigned): int; overload;
    function getClientIndex(codecOut: tObject): int; overload;
    function getSrvIsActive(): bool;
    //
    procedure checkDriver(codec: TunavclWaveCodecDevice);
    procedure error(code, info: int);
    //
    function getClientOptions(clientIndex: unsigned): unsigned;
    procedure setClientOptions(clientIndex: unsigned; value: unsigned);
    //
    procedure onCodecOutDA(sender: unavclInOutPipe; data: pointer; len: unsigned);
    //
    procedure onAC2(connectionId: unsigned; var accept: bool);
    procedure onCE2(connectionId: unsigned; connected: bool);
    procedure onPacketEvent2(connectionId: unsigned; const packet: unavclInOutIPPacket);
  protected
    procedure timer(); override;
  public
    procedure afterConstruction(); override;
    procedure beforeDestruction(); override;
    //
    {DP:METHOD
      outFormatTag = -1 means outgoing codec will be same as incoming (per client);
    }
    function setAudioFormat(samplingRate: int = c_defSamplingRate; bitsPerSample: int = c_defBitsPerSample; numChannels: int = c_defNumChannels; outFormatTag: int = c_outFormatTag): HRESULT;
    function getAudioFormat(out format: unavclWavePipeFormatExchange): bool; overload;
    //
    function start(const port: string; connType: tunavclProtoType = unapt_UDP): HRESULT;
    procedure stop();
    function disconnectClient(connId: unsigned): bool;
    //
{$IFDEF DEBUG }
    function selfTest(): string;
{$ENDIF }
    //
    property clientCount: unsigned read f_clientCount;
    property clientOptions[clientIndex: unsigned]: unsigned read getClientOptions write setClientOptions;
    //
    property server: unaConfIPServer read f_ipServer;
    //
    property isActive: bool read getSrvIsActive;
    property mixedBytes: int64 read f_bcMixed;
    //
    property bytesSent: int64 read f_bytesSent;
    property bytesReceived: int64 read f_bytesReceived;
    //
    property onAcceptClient: tunavclAcceptClient read f_onAC write f_onAC;
    property onClientEvent: tunavclConnectEvent read f_onCE write f_onCE;
    property onError: tunaConfError read f_onError write f_onError;
  end;


implementation


uses
  unaWave, unaMsAcmApi, unaSockets
{$IFDEF DEBUG }
  , SysUtils	// for Exceptions
{$ENDIF }
  ;


{ unaConfIPServer }

// --  --
constructor unaConfIPServer.createServer(master: unaConfServerClass);
begin
  f_master := master;
  //
{$IFDEF CS_LOG_MAX }
  logMessage(className + '.createServer() - server about to be created..');
{$ENDIF }
  //
  inherited create(nil);
end;

// --  --
procedure unaConfIPServer.doAcceptClient(connId: unsigned; var accept: bool);
begin
{$IFDEF CS_LOG_MAX }
  logMessage(className + '.doAcceptClient() - about to accept new client, connId=' + int2str(connId));
{$ENDIF }
  //
  f_master.onAC2(connId, accept);
  //
  inherited;
end;

// --  --
procedure unaConfIPServer.doServerClientConnection(connId: unsigned; isConnected: bool);
begin
{$IFDEF CS_LOG_MAX }
  logMessage(className + '.doServerClientConnection() - client connection, connId=' + int2str(connId) + '; isConnected = ' + bool2strStr(isConnected));
{$ENDIF }
  //
  f_master.onCE2(connId, isConnected);
  //
  inherited;
end;

// --  --
function unaConfIPServer.onNewPacket(const packet: unavclInOutIPPacket; connId: unsigned): bool;
begin
  f_master.onPacketEvent2(connId, packet);
  //
  result := inherited onNewPacket(packet, connId);
end;


{ unaCSSendThread }

// --  --
function unaCSSendThread.addSendRecord(connId: uint; cmd: uint; data: pointer; len: uint): bool;
var
  rx: punaCSSendThreadRecord;
begin
  if (100 > f_records.count) then begin	// sanity check
    //
    rx := malloc(sizeOf(rx^));
    //
    rx.r_connId := connId;
    rx.r_cmdu := cmd;
    rx.r_data := malloc(len, data);	// make local copy
    rx.r_lenu := len;
    //
    f_records.add(rx);
    //
    {$IFDEF DEBUG_EXTRA_DELAY }
    if (100 = random(10000)) then begin
      //
      if (f_records.lock(1000)) then try
	sleep(20);
      finally
	f_records.unlock();
      end;
    end;
    {$ENDIF }
    //
    start();	// just in case
    //
    result := true;
  end
  else
    result := false;
end;

// --  --
procedure unaCSSendThread.AfterConstruction();
begin
  f_records := unaRecordList.create();
  //
  inherited;
end;

// --  --
procedure unaCSSendThread.BeforeDestruction();
var
  i: int;
begin
  inherited;
  //
  if (0 < f_records.count) then begin
    //
    for i := 0 to f_records.count - 1 do
      mrealloc(punaCSSendThreadRecord(f_records.get(i)).r_data);
    //
  end;
  //
  freeAndNil(f_records);
end;

// --  --
constructor unaCSSendThread.create(master: unaConfServerClass);
begin
  f_master := master;
  //
  inherited create();
end;

{$IFDEF DEBUG_NASTY_EXCEPTION }

// --  --
function getEEInfo(E:PExceptionRecord): string;
begin
  if (nil <> E) then begin
    //
    result := 'Code: $' + int2str(E.ExceptionCode, 16) + '; ' +
	      'Flags: ' + int2str(E.ExceptionFlags) + '; ' +
	      'Record: [' + getEEInfo(E.ExceptionRecord) + ']; ' +
	      'Address: $' + int2str(uint(E.ExceptionAddress), 16) + '; ' +
	      'NumParams: ' + int2str(E.NumberParameters) + '; ' +
	      'Info: ' + base64encode(@E.ExceptionInformation, sizeOf(E.ExceptionInformation))
  end
  else
    result := '<NULL>';
end;

{$ENDIF }

// --  --
function unaCSSendThread.execute(threadId: uint): int;
var
  rx: punaCSSendThreadRecord;
  i: int;
  idx: int;
  res: tsendResult;
begin
  while (not shouldStop) do begin
    //
    try
      if (lockNonEmptyList(f_records, 10)) then begin
	//
	try
	  //
  {$IFDEF CS_LOG_MAX }
	  logMessage(className + '.execute() - about to send ' + int2str(f_records.count) + ' packets to cleint(s)..');
  {$ENDIF }
	  for i := 0 to f_records.count - 1 do begin
	    //
	    rx := punaCSSendThreadRecord(f_records.get(i));
	    //
	    res := f_master.f_ipServer.doSendPacket(rx.r_connId, rx.r_cmdu, rx.r_data, rx.r_lenu);
  {$IFDEF CS_LOG_MAX }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -