SoftPhone. Система голосових дзвінків

Автор работы: Пользователь скрыл имя, 25 Июня 2013 в 22:01, дипломная работа

Краткое описание

Останім часом все ширше стає застосовуватись мережі Інтернет. І якщо років 10 тому аналітики заперечували можливість передачі голосу і відео через мережу Інтернет, то сьогодні їхні погляди на ці речі повністю змінились. Наприклад, з прогнозу дослідницької фірми Analysys у 2003 році на Інтернет-телефонію буде припадати 36% всіх міждународних переговорів.
Великим поштовхом для прогресивного розвитку Інтернет-телефонії стало те що використання мережі Інтернет для передавання голосових і відео повідомлень є досить зручним і є набагато дешевшим чим звичайний телефоний дзвінок.
ІР - телефонія , за допомогою Інтернету дозволяє організовувати дзвінки між комп'ютерами . В ІР - телефонії використовуються канали зв'язку мережі Інтернет. При розмові наші голосові сигнали перетворюються в пакети даних які стискаються

Содержание

ВСТУП 9
Розділ 1. IP - ТЕЛЕФОНІЯ і SIP ПРОТОКОЛ 13
1.1. Історія розвитку ІР - телефонії 13
1.2. Принцип дії ІР - телефонії 13
1.3. Якість Зв'язку ІР - телефонії 14
1.4. Протокол SIP 16
1.5.Можливості протоколу SIP 17
1.6. Повідомлення SIP 18
1.7. Приклад встановлення з'єднання 20
1.8.Мережа на базі протоколу SIP 22
1.9. Висновок до першого розділу 26
2. ВИБІР ЗАСОБІВ ДЛЯ РЕАЛІЗАЦІЇ ПРОГРАМИ 27
2.1. Вибір мови програмування 27
2.2. Опис мови програмування і її основні елементи 27
2.3. Структура програми 29
2.4. Характеристики Delphi SIP Component 31
2.5. Вимог до апаратних 32
2.6. Призначення програми 32
2.7. Вимоги до програми загалом 32
2.8. Розробка узагальненого алгоритму функціонування програми 33
2.9. Висновок до другого розділу 35
3. ПРОГРАМНА РЕАЛІЗАЦІЯ СИСТЕМИ 36
3.1. Розробка архітектури програмного рішення 36
3.1.1. MainForm - головне вікно 36
3.1.2 DialForm - форма дизайну і розташування всіх компонентів 37
3.1.3 AudiFrm - форма налаштування звуку. 38
3.1.4 AccountsFrm - форма налаштування користувачів. 39
3.2. Проектування інтерфейсу користувача 40
3.2.1 Головне вікно 40
3.2.2 Вікно "Account Settings" 41
3.2.3 Вікно "Audio Settings" 43
3.2.4 Вікно "About" 43
3.2.5 Розробка діаграм функцій для програми. 44
3.3. Тестування роботи програми 51
3.4. Висновок до третього розділу 53
4. ЕКОНОМІЧНА ЧАСТИНА 54
4.1. Розрахунок витрат на розробку та впровадження проектного рішення 54
4.3. Визначення комплексного показника якості 60
4.4. Визначення експлуатаційних витрат 62
4.5. Розрахунок ціни споживання проектного рішення 64
4.6. Визначення показників економічної ефективності 65
4.6.1. Показник конкурентоздатності: 65
4.6.2. Економічний ефект в сфері проектування рішення: 65
4.6.3. Економічний ефект в сфері експлуатації : 65
4.6.4. Оскільки Епр>0 і Еекс>0, розраховуємо додатковий економічний ефект в сфері проектування: 66
4.6.5. Сумарний ефект 66
4.7.Висновок до четвертого розділу 67
ВИСНОВОК 68

Вложенные файлы: 1 файл

1True1.docx

— 1.12 Мб (Скачать файл)

{$R *.dfm}

 

{ TMainForm }

 

procedure TMainForm.FormShow(Sender: TObject);

var

  DevOutCaps: TWaveOutCaps;

  DevInCaps: TWaveInCaps;

  n, i: Integer;

  s: String;

  Ini: TIniFile;

begin

  FLineIndex := 1;

 

 

 

  RefreshLines;

 

  FRingThread := nil;

 

  Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+IniFileName);

   try

        TDialFrm1.PhoneEdit.Text := Ini.ReadString('CALL', 'Phone', TDialFrm1.PhoneEdit.Text);

    SipClient.LocalPort := Ini.ReadInteger('SIP', 'LocalPort', SipClient.LocalPort);

  finally

    Ini.Free;

  end;

 

  TAudioFrm1.waveOutDevice.Items.Clear;

  TAudioFrm1.waveOutDevice.Items.AddObject('Default', TObject(WAVE_MAPPER));

  n := waveOutGetNumDevs;

  for i := 0 to n-1 do

  begin

    waveOutGetDevCaps(i, @DevOutCaps, SizeOf(DevOutCaps));

    s := PChar(@DevOutCaps.szPname);

    TAudioFrm1.waveOutDevice.Items.Add(s);

  end;

  TAudioFrm1.waveInDevice.Items.Clear;

  TAudioFrm1.waveInDevice.Items.AddObject('Default', TObject(WAVE_MAPPER));

  n := waveInGetNumDevs;

  for i := 0 to n-1 do

  begin

    waveInGetDevCaps(i, @DevInCaps, SizeOf(DevInCaps));

    s := PChar(@DevInCaps.szPname);

    TAudioFrm1.waveInDevice.Items.Add(s);

  end;

  TAudioFrm1.waveRingDevice.Items.Clear;

  TAudioFrm1.waveRingDevice.Items.AddObject('Default', TObject(WAVE_MAPPER));

  n := waveOutGetNumDevs;

  for i := 0 to n-1 do

  begin

    waveOutGetDevCaps(i, @DevOutCaps, SizeOf(DevOutCaps));

    s := PChar(@DevOutCaps.szPname);

    TAudioFrm1.waveRingDevice.Items.Add(s);

  end;

 

  TAudioFrm1.waveOutDevice.ItemIndex := 0;

  TAudioFrm1.waveInDevice.ItemIndex := 0;

  TAudioFrm1.waveRingDevice.ItemIndex := 0;

 

  LoadAccountInfo;

 

  SipClient.Active := True;

 

  if (ServerEditText <> '') and (UserEditText <> '') then

  begin

    OnlineMenuClick(Self);

  end;

  Timer1.Enabled:=True;

end;

 

procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);

var

  Ini: TIniFile;

begin

  FreeAndNil(FRingThread);

  Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+IniFileName);

  try

    Ini.WriteString('CALL', 'Phone', TDialFrm1.PhoneEdit.Text);

  finally

    Ini.Free;

  end;

  SaveAccountInfo; 

end;

 

procedure TMainForm.InfoBtnClick(Sender: TObject);

begin

  if Assigned(FLines[FLineIndex]) and (FLines[FLineIndex].State = csActive) then

  begin

    case TSpeedButton(Sender).Tag of

     0: SipClient.SendDtmf(FLines[FLineIndex], '0');

     1: SipClient.SendDtmf(FLines[FLineIndex], '1');

     2: SipClient.SendDtmf(FLines[FLineIndex], '2');

     3: SipClient.SendDtmf(FLines[FLineIndex], '3');

     4: SipClient.SendDtmf(FLines[FLineIndex], '4');

     5: SipClient.SendDtmf(FLines[FLineIndex], '5');

     6: SipClient.SendDtmf(FLines[FLineIndex], '6');

     7: SipClient.SendDtmf(FLines[FLineIndex], '7');

     8: SipClient.SendDtmf(FLines[FLineIndex], '8');

     9: SipClient.SendDtmf(FLines[FLineIndex], '9');

    10: SipClient.SendDtmf(FLines[FLineIndex], '*');

    11: SipClient.SendDtmf(FLines[FLineIndex], '#');

    end;

  end

  else

    if TSpeedButton(Sender).Tag in [0,1,2,3,4,5,6,7,8,9] then

      TDialFrm1.PhoneEdit.Text := TDialFrm1.PhoneEdit.Text + IntToStr(TSpeedButton(Sender).Tag)

    else

    if TSpeedButton(Sender).Tag = 10 then

      TDialFrm1.PhoneEdit.Text := TDialFrm1.PhoneEdit.Text + '*'

    else

    if TSpeedButton(Sender).Tag = 11 then

      TDialFrm1.PhoneEdit.Text := TDialFrm1.PhoneEdit.Text + '#';

end;

 

procedure TMainForm.StatusBar1DrawPanel(StatusBar: TStatusBar;

  Panel: TStatusPanel; const Rect: TRect);

begin

  case Panel.Index of

  0:

  begin

    StatusImages.Draw(StatusBar1.Canvas,Rect.Left,Rect.Top, 0, FConnected);

    StatusBar1.Canvas.Font.Color := clBlack;

    StatusBar1.Canvas.Brush.Style := bsClear;

    if not FConnected then

      StatusBar1.Canvas.TextOut(20, 3, 'Offline')

    else

    if Assigned(Account) then

      StatusBar1.Canvas.TextOut(20, 3, 'Àêê:'+Account.User+'@' + Account.Server);

  end

  end;

end;

 

procedure TMainForm.FormCreate(Sender: TObject);

begin

  FConnected := False;

end;

 

procedure TMainForm.StatusBar1Click(Sender: TObject);

begin

  StatusPopupMenu.Popup(Mouse.CursorPos.X, Mouse.CursorPos.Y);

end;

 

procedure TMainForm.OnlineMenuClick(Sender: TObject);

begin

  if not SipClient.Active then

    SipClient.Active := True;

  Account := SipClient.AddAccount(ServerEditText, UserEditText, PasswordEditText, ProxyEditText, STUNEditText);

  SipClient.RegisterAccount(Account);

end;

 

procedure TMainForm.OfflineMenuClick(Sender: TObject);

begin

  if SipClient.Active then

  begin

    if Assigned(Account) then

    begin

      SipClient.UnRegisterAccount(Account);

      StatusBar1.Repaint;

      OfflineMenu.Checked := True;

    end;

  end;

end;

 

procedure TMainForm.SipClientRegistrationOk(Sender: TObject;

  const AAccount: ISipAccount);

begin

  FConnected := True;

  StatusBar1.Repaint;

  OnlineMenu.Checked := True;

end;

 

procedure TMainForm.SipClientRegistrationBye(Sender: TObject;

  const AAccount: ISipAccount);

begin

  if Account = AAccount then

  begin

    Account := nil;

    FConnected := False;

  end;

  StatusBar1.Repaint;

  OfflineMenu.Checked := True;

end;

 

procedure TMainForm.SaveAccountInfo;

var

  Ini: TIniFile;

begin

  Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+IniFileName);

  try

    Ini.WriteString('ACCOUNT', 'STUN', STUNEditText);

    Ini.WriteString('ACCOUNT', 'Server', ServerEditText);

    Ini.WriteString('ACCOUNT', 'Proxy', ProxyEditText);

    Ini.WriteString('ACCOUNT', 'User', UserEditText);

    Ini.WriteString('ACCOUNT', 'Password', PasswordEditText);

    Ini.WriteString('AUDIO', 'In', TAudioFrm1.waveInDevice.Text);

    Ini.WriteString('AUDIO', 'Out', TAudioFrm1.waveOutDevice.Text);

    Ini.WriteString('AUDIO', 'Ring', TAudioFrm1.waveRingDevice.Text);

  finally

    Ini.Free;

  end;

end;

 

procedure TMainForm.LoadAccountInfo;

var

  Ini: TIniFile;

  i, cnt: Integer;

  s, u: String;

begin

  Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+IniFileName);

  try

    STUNEditText := Ini.ReadString('ACCOUNT', 'STUN','');

    ProxyEditText := Ini.ReadString('ACCOUNT', 'PROXY', '');

    ServerEditText := Ini.ReadString('ACCOUNT', 'Server','');

    UserEditText := Ini.ReadString('ACCOUNT', 'User','');

    PasswordEditText := Ini.ReadString('ACCOUNT', 'Password','');

 

    if Length(ServerEditText) > 0 then

    begin

      TAccountsFrm1.AccountList.Items.Add.Caption := ServerEditText;

      TAccountsFrm1.AccountList.Items[0].SubItems.Add(UserEditText);

    end;

 

    cnt := Ini.ReadInteger('ACCOUNT', 'Count',0);

 

    for i := 1 to cnt do

    begin

      s := Ini.ReadString('ACCOUNT'+IntToStr(i), 'Server','');

      u := Ini.ReadString('ACCOUNT'+IntToStr(i), 'User','');

      if (s <> ServerEditText) or (u <> UserEditText) then

      begin

        TAccountsFrm1.AccountList.Items.Add.Caption := s;

        TAccountsFrm1.AccountList.Items[TAccountsFrm1.AccountList.Items.Count-1].SubItems.Add(u);

      end;

    end;

 

    for i := 0 to TAudioFrm1.waveInDevice.Items.Count - 1 do

      if Trim(TAudioFrm1.waveInDevice.Items[i]) = Trim(Ini.ReadString('AUDIO', 'In','')) then

      begin

        TAudioFrm1.waveInDevice.ItemIndex := i;

        break;

      end;

    for i := 0 to TAudioFrm1.waveOutDevice.Items.Count - 1 do

      if Trim(TAudioFrm1.waveOutDevice.Items[i]) = Trim(Ini.ReadString('AUDIO', 'Out','')) then

      begin

        TAudioFrm1.waveOutDevice.ItemIndex := i;

        break;

      end;

    for i := 0 to TAudioFrm1.waveRingDevice.Items.Count - 1 do

      if Trim(TAudioFrm1.waveRingDevice.Items[i]) = Trim(Ini.ReadString('AUDIO', 'Ring','')) then

      begin

        TAudioFrm1.waveRingDevice.ItemIndex := i;

        break;

      end;

  finally

    Ini.Free;

  end;

end;

 

procedure TMainForm.HangUpActionExecute(Sender: TObject);

begin

  FreeAndNil(FRingThread);

  if Assigned(FLines[FLineIndex]) then

  begin

    if ((FLines[FLineIndex].State <> csRinging) or (FLines[FLineIndex].CallType = ctOutgoing)) then

    begin

      TDialFrm1.HangUpBtn.Enabled := False;

      SipClient.EndCall(FLines[FLineIndex]);

    end

  end;

end;

 

procedure TMainForm.CallActionExecute(Sender: TObject);

begin

  FreeAndNil(FRingThread);

  if Assigned(Account) then

  if not Assigned(FLines[FLineIndex]) then

  begin

    FLines[FLineIndex] := SipClient.AddCall(Account, TDialFrm1.PhoneEdit.Text,

      AudioInDeviceNameToDeviceID(TAudioFrm1.waveInDevice.Items[TAudioFrm1.waveInDevice.ItemIndex]),

      AudioOutDeviceNameToDeviceID(TAudioFrm1.waveOutDevice.Items[TAudioFrm1.waveOutDevice.ItemIndex]));

  end

  else

  if FLines[FLineIndex].State = csRinging then

  begin

    FLines[FLineIndex].AudioInDeviceID := AudioInDeviceNameToDeviceID(TAudioFrm1.waveInDevice.Items[TAudioFrm1.waveInDevice.ItemIndex]);

    FLines[FLineIndex].AudioOutDeviceID := AudioOutDeviceNameToDeviceID(TAudioFrm1.waveOutDevice.Items[TAudioFrm1.waveOutDevice.ItemIndex]);

    SipClient.AnswerCall(FLines[FLineIndex]);

  end;

end;

 

procedure TMainForm.CallActionUpdate(Sender: TObject);

begin

  CallAction.Enabled :=

    FConnected and

    ( not Assigned(FLines[FLineIndex]) or

      (Assigned(FLines[FLineIndex]) and (FLines[FLineIndex].State = csRinging) and (FLines[FLineIndex].CallType = ctIncoming))

    );

 

  TDialFrm1.CallBtn.Enabled := CallAction.Enabled;

end;

 

procedure TMainForm.HangUpActionUpdate(Sender: TObject);

begin

  HangUpAction.Enabled := Assigned(FLines[FLineIndex]) and

    (FLines[FLineIndex].State in [csActive, csRinging, csHold, csConnecting, csAutConnecting]);

  TDialFrm1.HangUpBtn.Enabled := HangUpAction.Enabled;

end;

 

procedure TMainForm.SipClientBye(Sender: TObject; const ACall: ISipCall);

var

  i: Integer;

begin

  FreeAndNil(FRingThread);

  for i := 1 to 6 do

  if FLines[i] = ACall then

  begin

    FLines[i] := nil;

    FDtmf[i] := '';

  end;

  RefreshLines;

end;

 

procedure TMainForm.SipClientInvite(Sender: TObject;

  const ACall: ISipCall);

var

  i, FreeLine: Integer;

begin

  FreeLine := 0;

  for i := 1 to 6 do

    if not Assigned(FLines[i]) then

    begin

      FreeLine := i;

      break;

    end;

  if FreeLine = 0 then

  begin

    SipClient.SendBusy(ACall);

  end

  else

  begin

    FLines[FreeLine] := ACall;

    FreeAndNil(FRingThread);

    FRingThread := TRingThread.Create(13);

  end;

end;

 

procedure TMainForm.SipClientInviteOk(Sender: TObject;

  const Call: ISipCall);

begin

  FreeAndNil(FRingThread);

end;

 

 

 

 

procedure TMainForm.TransferActionUpdate(Sender: TObject);

begin

  TransferAction.Enabled := Assigned(FLines[FLineIndex])

    and (FLines[FLineIndex].State in [csActive]);

end;

 

 

 

procedure TMainForm.RegisterActionExecute(Sender: TObject);

var

  s, u: String;

  idx: Integer;

  Ini: TIniFile;

  cur: Boolean;

  cnt, i: Integer;

begin

  Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+IniFileName);

  try

    s := TAccountsFrm1.AccountList.Selected.Caption;

    u := TAccountsFrm1.AccountList.Selected.SubItems[0];

    cur := (s = Ini.ReadString('ACCOUNT', 'Server','')) and

      (u = Ini.ReadString('ACCOUNT', 'User',''));

 

    cnt := Ini.ReadInteger('ACCOUNT', 'Count',0);

    idx := 0;

 

    if not cur then

    begin

      for i := 1 to cnt do

      begin

        if (s = Ini.ReadString('ACCOUNT'+IntToStr(i), 'Server','')) and

        (u = Ini.ReadString('ACCOUNT'+IntToStr(i), 'User','')) then

        begin

          PasswordEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'Password','');

          STUNEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'STUN','');

          ProxyEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'Proxy','');

          idx := i;

          break;

        end;

      end;

    end; 

 

    if not cur then

    begin

      OfflineMenuClick(nil);

      ServerEditText := s;

      UserEditText := u;

      PasswordEditText := Ini.ReadString('ACCOUNT'+IntToStr(idx), 'Password','');

      STUNEditText := Ini.ReadString('ACCOUNT'+IntToStr(idx), 'STUN','');

      ProxyEditText := Ini.ReadString('ACCOUNT'+IntToStr(idx), 'Proxy','');

      Ini.WriteString('ACCOUNT', 'Server',ServerEditText);

      Ini.WriteString('ACCOUNT', 'User',UserEditText);

      Ini.WriteString('ACCOUNT', 'Password',PasswordEditText);

      Ini.WriteString('ACCOUNT', 'STUN',STUNEditText);

      Ini.WriteString('ACCOUNT', 'Proxy', ProxyEditText);

    end;

   

  finally

    Ini.Free;

  end;

  if Assigned(Account) then

  begin

    FConnected := False;

    SipClient.UnRegisterAccount(Account);

  end;

  OnlineMenuClick(Self);

end;

 

procedure TMainForm.RegisterActionUpdate(Sender: TObject);

begin

  RegisterAction.Enabled :=

    (TAccountsFrm1.AccountList.Selected <> nil)

    and ((Assigned(Account)

    and ((Account.Server <> TAccountsFrm1.AccountList.Selected.Caption) or (Account.User <> TAccountsFrm1.AccountList.Selected.SubItems[0]))) or

    (not Assigned(Account)));

end;

 

procedure TMainForm.RemoveActionExecute(Sender: TObject);

var

  cnt, i: Integer;

  s, u: String;

  sl, ul, pl, tl: TStringList;

  cur: Boolean;

  Ini: TIniFile;

begin

  if TAccountsFrm1.AccountList.Selected <> nil then

    if MessageBox(Handle, PChar(Format('Do you want to remove account %s@%s ?',

      [TAccountsFrm1.AccountList.Selected.SubItems[0], TAccountsFrm1.AccountList.Selected.Caption])), 'Confirm', MB_YESNO + MB_ICONWARNING) <> mrYes then

        Exit;

  Ini := TIniFile.Create(ExtractFilePath(ParamStr(0))+IniFileName);

  try

    if TAccountsFrm1.AccountList.Selected <> nil then

    if TAccountsFrm1.AccountList.Items.Count > 0 then

    begin

      s := TAccountsFrm1.AccountList.Selected.Caption;

      u := TAccountsFrm1.AccountList.Selected.SubItems[0];

      cur := (ServerEditText = s) and (UserEditText = u);

      if cur then

      begin

        OfflineMenuClick(nil);

      end;

 

      cnt := Ini.ReadInteger('ACCOUNT', 'Count',0);

      if cnt > 0 then

      begin

        sl := TStringList.Create;

        ul := TStringList.Create;

        pl := TStringList.Create;

        tl := TStringList.Create;

        try

          for i := 1 to cnt do

          begin

            if (s <> Ini.ReadString('ACCOUNT'+IntToStr(i), 'Server','')) or

            (u <> Ini.ReadString('ACCOUNT'+IntToStr(i), 'User','')) then

            begin

              sl.Add(Ini.ReadString('ACCOUNT'+IntToStr(i), 'Server',''));

              ul.Add(Ini.ReadString('ACCOUNT'+IntToStr(i), 'User',''));

              pl.Add(Ini.ReadString('ACCOUNT'+IntToStr(i), 'Password',''));

              tl.Add(Ini.ReadString('ACCOUNT'+IntToStr(i), 'STUN',''));

            end;

            Ini.EraseSection('ACCOUNT'+IntToStr(i));

          end;

 

          for i := 0 to sl.Count - 1 do

          begin

            Ini.WriteString('ACCOUNT'+IntToStr(i+1), 'Server',sl[i]);

            Ini.WriteString('ACCOUNT'+IntToStr(i+1), 'User',ul[i]);

            Ini.WriteString('ACCOUNT'+IntToStr(i+1), 'Password',pl[i]);

            Ini.WriteString('ACCOUNT'+IntToStr(i+1), 'STUN',tl[i]);

          end;

          Ini.WriteInteger('ACCOUNT', 'Count', sl.Count);

        finally

          sl.Free;

          ul.Free;

          pl.Free;

          tl.Free;

        end;

      end;

      TAccountsFrm1.AccountList.Items.Delete(TAccountsFrm1.AccountList.Selected.Index);

      if cur then

      begin

        ServerEditText := '';

        UserEditText := '';

        PasswordEditText := '';

        STUNEditText := '';

        ProxyEditText := '';

      end;

      if TAccountsFrm1.AccountList.Items.Count > 0 then

      begin

        TAccountsFrm1.AccountList.Items[0].Focused := True;

        TAccountsFrm1.AccountList.Items[0].Selected := True;

        s := TAccountsFrm1.AccountList.Selected.Caption;

        u := TAccountsFrm1.AccountList.Selected.SubItems[0];

        cnt := Ini.ReadInteger('ACCOUNT', 'Count',0);

        for i := 1 to cnt do

        if (s = Ini.ReadString('ACCOUNT'+IntToStr(i), 'Server',''))

        and (u = Ini.ReadString('ACCOUNT'+IntToStr(i), 'User','')) then

        begin

          ServerEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'Server','');

          UserEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'User','');

          PasswordEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'Password','');

          STUNEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'STUN','');

          ProxyEditText := Ini.ReadString('ACCOUNT'+IntToStr(i), 'Proxy', '');

          break;

        end;

        Ini.WriteString('ACCOUNT', 'Server', ServerEditText);

        Ini.WriteString('ACCOUNT', 'User', UserEditText);

Информация о работе SoftPhone. Система голосових дзвінків