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

📄 unaconfserver.pas

📁 Voice Commnucation Components for Delphi
💻 PAS
📖 第 1 页 / 共 3 页
字号:
{$ENDIF }
      end;
      //
    finally
      f_clientLock.leave();
    end;
end;

// --  --
procedure unaConfServerClass.onCodecOutDA(sender: unavclInOutPipe; data: pointer; len: unsigned);
var
  res: bool;
  clientIndex: int;
begin
  if ((0 < len) and (nil <> data)) then begin
    //
    clientIndex := getClientIndex(sender);
    if (0 > clientIndex) then
       clientIndex := -1;
    //
    if ((0 <= clientIndex) and (0 < f_clients[clientIndex].r_connId)) then begin
      //
{$IFDEF CS_LOG_MAX }
      logMessage(className + '.onCodecOutDA() - need to send ' + int2str(len) + ' bytes to client, index=' + int2str(clientIndex));
{$ENDIF }
      // send audio back to specific client
      //res := f_ipServer.doSendPacket(f_clients[clientIndex].r_connId, cmd_inOutIPPacket_audio, data, len);
      res := f_senderThread.addSendRecord(f_clients[clientIndex].r_connId, cmd_inOutIPPacket_audio, data, len);
      //
      if (res) then
	inc(f_bytesSent, len);
      //
    end
    else
{$IFDEF CS_LOG_MAX }
      logMessage(className + '.onCodecOutDA() - cannot locate index for sender=' + int2str(uint(sender), 16));
{$ENDIF }
  end;
end;

// --  --
procedure unaConfServerClass.onPacketEvent2(connectionId: unsigned; const packet: unavclInOutIPPacket);
var
  clientIndex: int;
begin
  if ((0 < clientCount) and (0 < packet.r_dataSize) and f_clientLock.enter(500)) then begin
    try
      //
      inc(f_bytesReceived, packet.r_dataSize);
      //
      clientIndex := getClientIndex(connectionId);
      if (0 <= clientIndex) then begin
	//
	case (packet.r_command) of

	  cmd_inOutIPPacket_audio: begin
	    //
{$IFDEF CS_LOG_MAX }
	    logMessage(className + '.onPacketEvent2() - NetA -> CodecIn, connId=' + int2str(connectionId) + '; index=' + int2str(clientIndex) + '; size=' + int2str(packet.r_dataSize));
{$ENDIF }
	    f_clients[clientIndex].r_codecIn.write(@packet.r_data, packet.r_dataSize);
	  end;

	  cmd_inOutIPPacket_formatAudio: begin
	    //
{$IFDEF CS_LOG_MAX }
	    logMessage(className + '.onPacketEvent2() - got new audio format packet, connId=' + int2str(connectionId) + '; index=' + int2str(clientIndex) + '; size=' + int2str(packet.r_dataSize));
{$ENDIF }
	    // apply codecIn format
	    with (punavclWavePipeFormatExchange(@packet.r_data)^) do begin
	      //
	      if ((int(r_format.formatOriginal.pcmSamplesPerSecond) = f_samplingRate) and
		  (int(r_format.formatOriginal.pcmBitsPerSample) = f_bitsPerSample) and
		  (int(r_format.formatOriginal.pcmNumChannels) = f_numChannels)) then begin
		//
		with (f_clients[clientIndex]) do begin
		  //
		  if (r_codecIn.active) then begin
		    // should not be here
		    r_codecIn.close();
		  end;
		  //
		  if (r_codecOut.active) then begin
		    // should not be here
		    r_codecOut.close();
		  end;
		  //
		  r_codecIn.pcm_samplesPerSec := r_format.formatOriginal.pcmSamplesPerSecond;
		  r_codecIn.pcm_bitsPerSample := r_format.formatOriginal.pcmBitsPerSample;
		  r_codecIn.pcm_numChannels := r_format.formatOriginal.pcmNumChannels;
		  r_codecIn.formatTag := r_format.formatTag; // DEBUG_DUMMY_CODEC: 12345678
		  //
		  r_codecOut.pcm_samplesPerSec := r_format.formatOriginal.pcmSamplesPerSecond;
		  r_codecOut.pcm_bitsPerSample := r_format.formatOriginal.pcmBitsPerSample;
		  r_codecOut.pcm_numChannels := r_format.formatOriginal.pcmNumChannels;
		  //
		  if (0 > f_outFormatTag) then
		    r_codecOut.formatTag := r_format.formatTag
		  else
		    r_codecOut.formatTag := f_outFormatTag;
		  //
		  checkDriver(r_codecIn);
		  checkDriver(r_codecOut);
		  //
{$IFDEF CS_LOG_MAX }
		  logMessage(className + '.onPacketEvent2() - IN CODEC [' + codecInfo(r_codecIn) + ']   OUT CODEC [' + codecInfo(r_codecOut) + ']');
{$ENDIF }
		end;
		//
	      end;
	    end;
	  end;

	  cmd_inOutIPPacket_userData: begin
{$IFDEF CS_LOG_MAX }
	    logMessage(className + '.onPacketEvent2() - got new user data packet, connId=' + int2str(connectionId) + '; index=' + int2str(clientIndex) + '; size=' + int2str(packet.r_dataSize));
{$ENDIF }
	    // distribute client's data among all clients
	    f_ipServer.sendPacket(0, cmd_inOutIPPacket_userData, @packet.r_data, packet.r_dataSize);
	  end;

	end;
      end
      else begin
{$IFDEF CS_LOG_MAX }
	logMessage(className + '.onPacketEvent2() - could not locate the client for connId=' + int2str(connectionId));
{$ENDIF }
      end;
      //
    finally
      f_clientLock.leave();
    end;
  end
  else begin
{$IFDEF CS_LOG_MAX }
    logMessage(className + '.onPacketEvent2() - could not lock the gate, no data or no clients..');
{$ENDIF }
  end;
end;

// --  --
function unaConfServerClass.setAudioFormat(samplingRate, bitsPerSample, numChannels, outFormatTag: int): HRESULT;
var
  q: double;
begin
  if ((1000   <= samplingRate) and (8  <= bitsPerSample) and (1  <= numChannels) and
      (200000 >= samplingRate) and (32 >= bitsPerSample) and (16 >= numChannels)
     ) then begin
    //
    q := (samplingRate * numChannels * (bitsPerSample shr 3)) / c_ticksPerSecond;
    if (trunc(q) * c_ticksPerSecond = (samplingRate * numChannels * (bitsPerSample shr 3))) then begin
      //
      f_samplingRate := samplingRate;
      f_bitsPerSample := bitsPerSample;
      f_numChannels := numChannels;
      //
      f_outFormatTag := outFormatTag;
      //
      f_mixer.setSampling(f_samplingRate, f_bitsPerSample, f_numChannels);
      //
      f_mixBufSize := (f_samplingRate * f_numChannels * (f_bitsPerSample shr 3)) div c_ticksPerSecond;
      mrealloc(f_mixBuf, f_mixBufSize);
      //
      result := S_OK;
      //
{$IFDEF CS_LOG_MAX }
     logMessage(className + '.setAudioFormat() - set (formatTag=' + int2str(f_outFormatTag) + '; SPS=' + int2str(f_samplingRate) + '; BPS=' + int2str(f_bitsPerSample) + '; NC=' + int2str(f_numChannels) + '; MIX BUFFER SIZE=' + int2str(f_mixBufSize) + ')');
{$ENDIF }
    end
    else begin
      //
      result := -2;
{$IFDEF CS_LOG_MAX }
      logMessage(className + '.setAudioFormat() - bad Q');
{$ENDIF }
    end;
    //
  end
  else begin
    //
    result := -1;
    //
{$IFDEF CS_LOG_MAX }
    logMessage(className + '.setAudioFormat() - bad params');
{$ENDIF }
  end;
end;

// --  --
procedure unaConfServerClass.setClientOptions(clientIndex: unsigned; value: unsigned);
begin
  f_ipServer.clientOptions[clientIndex] := value;
end;

// --  --
function unaConfServerClass.start(const port: string; connType: tunavclProtoType): HRESULT;
var
  format: unavclWavePipeFormatExchange;
begin
{$IFDEF CS_LOG_MAX }
  logMessage(className + '.start() - server about to be started..');
{$ENDIF }
  //
  f_ipServer.port := port;
  f_ipServer.proto := connType;
  //
  f_bytesSent := 0;
  f_bytesReceived := 0;
  //
  getAudioFormat(format);
  //
  f_ipServer.open();
  f_ipServer.applyFormat(@format, sizeof(format));
  //
  inherited start();
  //
  if (f_ipServer.active) then
    result := S_OK
  else
    result := -1;
  //
end;

// --  --
procedure unaConfServerClass.stop();
begin
{$IFDEF CS_LOG_MAX }
  logMessage(className + '.start() - server about to be stopped..');
{$ENDIF }
  //
  inherited stop();
  //
  f_senderThread.stop();
  //
  f_ipServer.close();
end;

// --  --
procedure unaConfServerClass.timer();
var
  i: unsigned;
  sz: unsigned;
  bufClean: bool;
begin
  if ((0 < f_lastTimerTick) or (4 < timeElapsed32(f_lastTimerTick))) then begin
    //
    f_lastTimerTick := timeMark();
    // mix buffers
    if ((0 < clientCount) and f_clientLock.enter(interval - 10)) then begin
      //
      try
	i := 0;
	bufClean := false;
	while (i < c_maxClients) do begin
	  //
	  if (0 <> f_clients[i].r_connId) then begin	// no need, since mixer will fill missing buffer automatically
	    //
	    sz := f_clients[i].r_codecIn.read(f_mixBuf, f_mixBufSize);
	    if (sz < f_mixBufSize) then begin
	      //
	      if (bufClean and (1 > sz)) then
	      else
		// fill buffer with silence
		fillChar(f_mixBuf[sz], f_mixBufSize - sz, #0);
	      //
    {$IFDEF CS_LOG_MAX }
	      logMessage(className + '.timer() - silence has to be added, SoS=' + int2str(f_mixBufSize - sz) + ' bytes; index=' + int2str(i));
    {$ENDIF }
	      bufClean := (1 > sz);
	    end
	    else
	      bufClean := false;
	    //
	    f_clients[i].r_mixerStream.write(f_mixBuf, f_mixBufSize);
	  end
	  else
	    f_clients[i].r_mixerStream.clear();
	  //
	  inc(i);
	end;
	//
	inc(f_bcMixed, f_mixer.pump(f_mixBufSize));
	//
  {$IFDEF CS_LOG_MAX }
	logMessage(className + '.timer() - mixed ' + int2str(f_mixBufSize) + ' bytes; ');
  {$ENDIF }
	//
	i := 0;
	while (i < c_maxClients) do begin
	  //
	  if (0 <> f_clients[i].r_connId) then begin	// we can skip reading from a stream, since mixer will clean it internally anyway
	    //
	    sz := f_clients[i].r_mixerStream.read(f_mixBuf, f_mixBufSize);
	    if (0 < sz) then begin
	    //
  {$IFDEF CS_LOG_MAX }
	      logMessage(className + '.timer() - about to feed codec#' + int2str(i));
  {$ENDIF }
	      f_clients[i].r_codecOut.write(f_mixBuf, sz);
	    end;
	  end;
	  //
	  inc(i);
	end;
	//
      finally
	f_clientLock.leave();
      end;
    end;
  end;
end;


{$IFDEF DEBUG }

// --  --
function unaConfServerClass.selfTest(): string;
var
  i: int;
  res: bool;
  cad: array[boolean, boolean] of int64;
  th: unaSocksThread;
begin
  th := f_ipServer.socks.getThreadByID(f_ipServer.socksId);
  //
  if (nil <> th) then
    result := 'Server is running, port=' + th.socket.getPort() + '; type=' + int2str(th.socket.socketType)
  else
    result := 'Server seems to be not activated';
  //
  // 1. check how many active clients we have now
  result := result + #13#10'Active Clients:';
  //
  i := 0;
  while (i < int(c_maxClients)) do begin
    //
    try
      cad[false][false] := f_clients[i].r_codecIn.inBytes;
      cad[false][true]  := f_clients[i].r_codecIn.outBytes;
      cad[true][false]  := f_clients[i].r_codecOut.inBytes;
      cad[true][true]   := f_clients[i].r_codecOut.outBytes;
      //
      result := result + #13#10'[' + int2str(i) + '] - connId=' + int2str(f_clients[i].r_connId) +
			 '; CIA=' + bool2strStr(f_clients[i].r_codecIn.active) +
			 '; COA=' + bool2strStr(f_clients[i].r_codecOut.active) + ' [' + int2str(getClientIndex(f_clients[i].r_codecOut)) + ']' +
			 '; '
		 ;
      if (0 < f_clients[i].r_connId) then begin
	//
	res := f_senderThread.addSendRecord(f_clients[i].r_connId, cmd_inOutIPPacket_userData, @i, sizeOf(i));
	//
	result := result + 'ASR=' + bool2strStr(res) + '; S_OK=' + int2str(f_senderThread.f_sentOK[i]) + '; S_FAIL=' + int2str(f_senderThread.f_sentFail[i]);
      end;
      //
      sleep(200);
      //
      cad[false][false] := f_clients[i].r_codecIn.inBytes   - cad[false][false];
      cad[false][true]  := f_clients[i].r_codecIn.outBytes  - cad[false][true];
      cad[true][false]  := f_clients[i].r_codecOut.inBytes  - cad[true][false];
      cad[true][true]   := f_clients[i].r_codecOut.outBytes - cad[true][true];
      //
      result := result + ' [ iI:' + int2str(cad[false][false]) + ' / ' +
			    'iO:' + int2str(cad[false][true])  + ' / ' +
			    'oI:' + int2str(cad[true][false])  + ' / ' +
			    'oO:' + int2str(cad[true][true]) +
			 ' ]';
    except
      //
{$IFDEF DEBUG_NASTY_EXCEPTION }
      on E: EExternal do begin
	//
	result := result + ' ..EExternal.. ';
	logMessage(className + '.selfTest() - got exception [' + E.Message + '], info: ' + getEEInfo(E.ExceptionRecord));
      end;

      on E: Exception do begin
	//
	result := result + ' ..Exception.. ';
	logMessage(className + '.selfTest() - got exception [' + E.Message + ']');
      end;
{$ELSE }
      //
{$ENDIF }
    end;
    //
    inc(i);
  end;
  //
end;

{$ENDIF }


end.

⌨️ 快捷键说明

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