Solved

indy Spirating Server and client and broadcast audio

Posted on 2014-09-27
9
315 Views
Last Modified: 2014-10-02
iam creating audio stream chat application i stick with problems because i started the project and puts client and server in same project and and iam unable to broadcast  data to all connected clients i searched alot and i see something said i have  to separated the server and client without understanding what does that means and how to implement this in my current code here is my current code

const
  WAVE_FORMAT_GSM610 = $0031;

type
  PGSM610WaveFormat = ^TGSM610WaveFormat;
  TGSM610WaveFormat = record
  wfx: TWaveFormatEx;
  wSamplesPerBlock: Word;
  end;

type
  TAudioBuffer = class
  private
    CS: RTL_CRITICAL_SECTION;
    Data: Pointer;
    Size: Cardinal;
  public
    EnterCritial : Boolean;
    constructor Create;
    destructor Destroy; override;
    procedure Clear;
    function BeginUpdate(ExtraSize: Cardinal): Pointer;
    procedure EndUpdate;
    function Get(out Buffer: Pointer; out BufferSize: Cardinal): Boolean;
  end;

{ TAudioBuffers }

constructor TAudioBuffer.Create;
begin
  InitializeCriticalSection(CS);
end;

destructor TAudioBuffer.Destroy;
begin
  Clear;
  DeleteCriticalSection(CS);
  inherited Destroy;
end;

procedure TAudioBuffer.Clear;
begin
  EnterCriticalSection(CS);
  try
    ReallocMem(Data, 0);
    Size := 0;
  finally
    LeaveCriticalSection(CS);
  end;
end;

function TAudioBuffer.BeginUpdate(ExtraSize: Cardinal): Pointer;
begin
  EnterCriticalSection(CS);
  EnterCritial := True;
  ReallocMem(Data, Size + ExtraSize);
  Result := Pointer(Cardinal(Data) + Size);
  Inc(Size, ExtraSize);
end;

procedure TAudioBuffer.EndUpdate;
begin
  LeaveCriticalSection(CS);
  EnterCritial := False;
end;

function TAudioBuffer.Get(out Buffer: Pointer; out BufferSize: Cardinal): Boolean;
begin
  EnterCriticalSection(CS);
  try
    Result := False;
    if Assigned(Data) then
    begin
      Buffer := Data;
      BufferSize := Size;
      Data := nil;
      Size := 0;
      Result := True;
    end;
  finally
    LeaveCriticalSection(CS);
  end;
end;
//send audio
procedure TChatFo.recorderData(Sender: TObject; const Buffer: Pointer;
  BufferSize: Cardinal; var FreeIt: Boolean);
var
  Bytes: TIdBytes;
begin
  Freeit := True;
  if Tcli.Connected then
  begin
    if (Buffer <> nil) and (Buffersize > 0) then
    begin
      try
        Bytes := RawToBytes(Buffer^, Buffersize);
      except
        micstop.Caption := 'Invalid !';
        Exit;
      end;
      begin
      Tcli.IOHandler.WriteLn('AUDIO');
      Tcli.IOHandler.Write(BufferSize);
      Tcli.IOHandler.Write(Bytes);
    end;
    end
     else
      micstop.Caption := 'Server error!';
  end else
    micstop.Caption := 'Not connected';
end;


procedure TChatFo.BroadcastAudio(Audio: string);
var
  List: TList;
  I: Integer;
begin
  List := Tserv.Contexts.LockList;
  try
    for I := 0 to List.Count - 1 do
      TIdContext(List[i]).Connection.IOHandler.Write(Audio);
  finally
    Tserv.Contexts.UnlockList;
  end;
end;

// server execute part

procedure TChatFo.TservExecute(AContext: TIdContext);
var
 Cmd,
  TextMessage: String;
  AUDIO: String;
  AudioDataSize: Integer;
  AudioDataBytes: TIdBytes;
  AudioData : Pointer;
begin
  Cmd :=  AContext.Connection.IOHandler.ReadLn;
  if Cmd = 'TEXTMESSAGE' then
  begin
    TextMessage := AContext.Connection.IOHandler.ReadLn;
    BroadcastMessage(TextMessage);
    with TMemoSync.Create do
  try
    FText := TextMessage;
    Synchronize;
  finally
    Free;
  end;
  end
  else if Cmd = 'AUDIO' then
begin
try
 InitializeCriticalSection(Section);
    EnterCriticalSection(Section);
    try
      Sleep(0);
      AudioDataSize := AContext.Connection.IOHandler.ReadLongInt();
      AContext.Connection.IOHandler.ReadBytes(AudioDataBytes, AudioDataSize);
      BroadcastMessage(AUDIO);
      if AudioDataSize > 10 then
      begin
        if not IsPlaying then AudioDataSize := 0;
        if AudioDataSize <> 0 then
      begin
        try
          if not ChatFo.Player.Active then
          begin
            ChatFo.Player.Active := True;
            ChatFo.Player.WaitForStart;
          end;
        except
        end;
        if BlockAlign > 1 then
          Dec(AudioDataSize, AudioDataSize mod BlockAlign);
        AudioData := AudioBuffer.BeginUpdate(AudioDataSize);
        try
          BytesToRaw(AudioDataBytes, AudioData^, AudioDataSize);
        finally
          AudioBuffer.EndUpdate;
        end;
      end else
      begin
        Player.Active := False;
        Player.WaitForStop;
      end;
      end;
    finally
      LeaveCriticalSection(Section);
    end;
except
    on e: exception do showmessage(e.Message)
  end;
end;
end;

Open in new window



i dont know how to do the same purpose if i separated the server and add the on execute code i will have errors because the components of audio that i use is only on client side to play sound can any body give me an example with my code how to do it in stand alone client and server ?
0
Comment
Question by:drama22
  • 5
  • 4
9 Comments
 
LVL 25

Expert Comment

by:Sinisa Vuk
Comment Utility
For such application - I use ICS components. But for example in Indy there are few in Delphi's Demos folder (ex. UPDClientServer). Depending what you want - peer to peer chat (when each side knows address of other clients) or server based chat - you should put client/server components. In peer to peer - each client is a server too. In server (central) based chat system - you must have one server app and few clients.
Decide what you want. Note: peer to peer - results in no load issue on server side ....
0
 

Author Comment

by:drama22
Comment Utility
In udp is easy to broadcast but udp cant work will on public server tcp is my using prefer I will try this ics but can you tell me now about indy tcp audio broadcast ? I already broadcsted text message but I fail in audio broadcasting .
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
Comment Utility
Indy, ICS ,.... components are just transport layer - all other is up to you. So, you decide to build one server-multiple client approach? What is a source of audio? Voice?
0
 

Author Comment

by:drama22
Comment Utility
iam using wave audio component

i be able to broadcast to all connected client a text message like this

this code on client side
procedure TChatFo.SendCommand(TCPClient: TIdTCPClient; Command: string);
begin
  if not TCPClient.Connected then
    Exit;
  TCPClient.Socket.WriteLn(Command);
end;

procedure TChatFo.SendCommandWithParams(TCPClient: TIdTCPClient; Command, Params: String);
var
 PackedParams: TPackedParams;
begin
  if not TCPClient.Connected then
    Exit;
  TCPClient.Socket.WriteLn('1' + Command);
  PackedParams.Params := ShortString(Params);
  TCPClient.Socket.Write(RawToBytes(PackedParams, SizeOf(PackedParams)));
end

Open in new window

;

and i send message like this
SendCommandWithParams(TCPClient, 'TEXTMESSAGE', strMsg + Sep);

Open in new window


i broadcast message in server side like this

procedure TServobj.BroadCastTextMessage(const TextMessage: String; const FromUniqueID: DWord;
  const FromName: string);
var
  I: Integer;
  Connection: TConnection;
begin
  for I := 0 to Connections.Count - 1 do
  begin
    Connection := Connections.Items[I];
    if Connection.UniqueID <> FromUniqueID then
      SendCommandWithParams(Connection, 'TEXTMESSAGE', FromName + Sep + TextMessage + Sep);
  end;
end;

Open in new window


but the audio part i cant figure it after i separated the server and client

before i separated the server and client i was doing it this way

This is how i send audio

procedure TChatFo.recorderData(Sender: TObject; const Buffer: Pointer;
  BufferSize: Cardinal; var FreeIt: Boolean);
var
  Bytes: TIdBytes;
begin
  Freeit := True;
  if Tcli.Connected then
  begin
    if (Buffer <> nil) and (Buffersize > 0) then
    begin
      try
        Bytes := RawToBytes(Buffer^, Buffersize);
      except
        micstop.Caption := 'Invalid !';
        Exit;
      end;
      begin
      Tcli.IOHandler.WriteLn('AUDIO');
      Tcli.IOHandler.Write(BufferSize);
      Tcli.IOHandler.Write(Bytes);
    end;
    end
     else
      micstop.Caption := 'Server error!';
  end else
    micstop.Caption := 'Not connected';
end;
  

Open in new window


this is how i was receive audio before separating the client and server

procedure TChatFo.TservExecute(AContext: TIdContext);
var
 Cmd,
  TextMessage: String;
  AUDIO: String;
  AudioDataSize: Integer;
  AudioDataBytes: TIdBytes;
  AudioData : Pointer;
begin
  Cmd :=  AContext.Connection.IOHandler.ReadLn;
  if Cmd = 'TEXTMESSAGE' then
  begin
    TextMessage := AContext.Connection.IOHandler.ReadLn;
    BroadcastMessage(TextMessage);
    with TMemoSync.Create do
  try
    FText := TextMessage;
    Synchronize;
  finally
    Free;
  end;
  end
  else if Cmd = 'AUDIO' then
begin
try
    EnterCriticalSection(Section);
    try
      Sleep(0);
      AudioDataSize := AContext.Connection.IOHandler.ReadLongInt();
      AContext.Connection.IOHandler.ReadBytes(AudioDataBytes, AudioDataSize);
      BroadcastMessage(AUDIO);
      if AudioDataSize > 10 then
      begin
        if not IsPlaying then AudioDataSize := 0;
        if AudioDataSize <> 0 then
      begin
        try
          if not ChatFo.Player.Active then
          begin
            ChatFo.Player.Active := True;
            ChatFo.Player.WaitForStart;
          end;
        except
        end;
        if BlockAlign > 1 then
          Dec(AudioDataSize, AudioDataSize mod BlockAlign);
        AudioData := AudioBuffer.BeginUpdate(AudioDataSize);
        try
          BytesToRaw(AudioDataBytes, AudioData^, AudioDataSize);
        finally
          AudioBuffer.EndUpdate;
        end;
      end else
      begin
        Player.Active := False;
        Player.WaitForStop;
      end;
      end;
    finally
      LeaveCriticalSection(Section);
    end;
except
    on e: exception do showmessage(e.Message)
  end;
end;
end;

Open in new window



but in the separated server and client i think i have to do somthing like this

How To send audio and correct me please

procedure TChatFo.recorderData(Sender: TObject; const Buffer: Pointer;
  BufferSize: Cardinal; var FreeIt: Boolean);
var
  Bytes: TIdBytes;
begin
  Freeit := True;
  if TCPClient.Connected then
  begin
    if (Buffer <> nil) and (Buffersize > 0) then
    begin
      try
        Bytes := RawToBytes(Buffer^, Buffersize);
      except
        micstop.Caption := 'Invalid !';
        Exit;
      end;
      begin
      SendCommandWithParams(TCPClient, 'AUDIO', BufferSize + Bytes);
    end;
    end
     else
      micstop.Caption := 'Server error!';
  end else
    micstop.Caption := 'Not connected';
end;

Open in new window



but the problem i dont know what to do in broadcast audio code in server project !

and how the client listen to audio that sent from other clients in text i do somthing like this

  if Command = 'TEXTMESSAGE' then
  begin
    memo1.Lines.Add( Params[1] + ' : ' + Params[2]);
  end;

Open in new window


but in audio what i have to do ?
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 

Author Comment

by:drama22
Comment Utility
I've requested that this question be deleted for the following reason:

did not found a resolve and i think its completely wrong question.
0
 
LVL 25

Accepted Solution

by:
Sinisa Vuk earned 500 total points
Comment Utility
Which version of Delphi do you have?
Small note: when you want to comunnicate through server - it will be very busy - all data from one client should be transfered to other....Do you think about that.
0
 

Author Comment

by:drama22
Comment Utility
i will find another way then Thank you Sinsa Vuk
0
 
LVL 25

Expert Comment

by:Sinisa Vuk
Comment Utility
Please Delphi version? I work on example so I need to know.
0
 

Author Comment

by:drama22
Comment Utility
Delphi xe 5
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This video discusses moving either the default database or any database to a new volume.
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now