На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! Соблюдайте общие правила форума
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.
Указывайте точные версии Delphi и используемых сетевых библиотек.

Не приветствуется поднятие старых тем. Если ваш вопрос перекликается со старой темой, то для вопроса лучше создать новую тему, а старую указать в первом сообщении с описанием взаимосвязи.

Внимание:
попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Krid, user posted image Rouse_

Модераторы: Krid, Rouse_
  
> как отловить момент поднятия телефонной трубки на другом конце линии?, создание звонилки
    Искал в поиске,гуглил, с периодичностью раз в 2-3 месяца данный вопрос
    проскальзывает и на нашем форуме, везде практически один и тотже ответ:
    "никак или чрезвычайно сложно". Нигде нет даже приблизительной
    реализации
    Тогда другой вопрос: каким образом это делают программы подобные
    VentaFax'у (кстати она тоже писана на дельфи)
    Сообщение отредактировано: Mr. Gonarh -
      Цитата Mr. Gonarh @
      Тогда другой вопрос: каким образом это делают программы подобные
      VentaFax'у (кстати она тоже писана на дельфи)

      Ожидают пилотного тона факса приемной стороны. :)
        Цитата
        Ожидают пилотного тона факса приемной стороны. :)

        для тех кто в танке: что такое пилотный тон факса
        кроме того какой может быть пилотный тон факса, если трубку снимает человек, VentaFax ловит это и начинает транслировать WAV файл в линию
          Через Tapi без понятия. На уровне AT команд, в принципе, можно. Если модем голосовой и аппаратно поддерживает соответсвующие функции.
          Методика примерно такая.
          AT#CLS=8 //перевод в голосовой режим
          ATD ... //набор номера, если нет тона станции или аб. занят, модем вернёт NO DIALTONE или BUSY вместо VCON.
          А вот дальше начинаем ловить сигнал контроля посылки вызова. Для этого нужно "слушать" модем. На сигнал КПВ(1 раз в 5 секунд) модем выдаёт комбинации из двух байт: <DLE>b. DLE=char($10).
          Вот эту комбинацию можно проверять. Кроме того, когда снимаешь трубку и начинаешь говорить, то получишь из модема целый букет всевозожных сигналов, которые он "распознал"в речевом сигнале. Если телефонная станция тмпользует специальный сигнал ответа, модем и его обнаружит. В общем, извратиться можно.
          Вот как-то так.

          Shielded codes sent to the DTE <DLE>0 - <DLE>9
          <DLE>* - <DLE>#
          <DLE>A - <DLE>D DTMF digits 0 to 9, *, # and A to D detected by the modem.
          <DLE>a Answer tone detected. V.25 or T.30.
          <DLE>b The BUSY signal is detected.
          <DLE>c The T.30 calling tone is detected.
          <DLE>d Dial tone is detected.
          <DLE>e The V.25 calling tone is detected.
          <DLE>f Bell answer tone is detected.
          <DLE>h Local handset has been hung up.
          <DLE>o An overrun has occurred in voice receive mode.
          <DLE>q Silence has been detected in voice receive mode and there has been valid voice previously detected.
          <DLE>s Silence has been detected in voice receive mode and there has not been valid voice previously detected.
          <DLE>t Local handset has been picked up.
          <DLE>u An under-run has occurred in voice transmit mode.
          <DLE><ETX> Acknowledgement to a key press abort in voice receive mode.


          Shielded codes sent from the DTE <DLE><ETX> Sent to indicate the end of voice transmission.
          <DLE><CAN> Sent to cancel current voice transmission and flush any data in the transmit buffer.
          <DLE>p Sent to pause the current voice transmission.
          <DLE>r Sent to resume a paused voice transmission.


          Добавлено
          У меня другой вопрос: как скормить wav модему? Этот вопрос тоже периодически всплывает и внятного ответа раз и навсегда пока не было.

          Добавлено

          -Added
          А, я ещё забыл самый очевидный вариант. Перевести модем в режим записи с линии (AT#VRX) и анализировать входящий аудиопоток ручками. ИМХО, самый надёжный вариант. Вот только как это правильно сделать. У меня пока не получилось(захват аудиопотока). Да я уже и забросил как-то эту задачу(тоже хотел звонилку сделать, а оказалось, что с моим модемом и VentaFax работает криво).
          Сообщение отредактировано: Prince -
          Человек человека понять не может.
            Обалдеть. Почти 10 лет прошло. В общем так. Пару недель назад опять пришлось столкнуться с задачей определения поднятия трубки. Пошукав по интернетам, перелопатив довольно таки огромное количество топиков на десятках различных форумах(на этот топик тоже через поиск наткнулся :lol: ), понял что единственный высоковероятностный метод определения поднятия трубки, это запись данных телефонной линии после набора номера, и спектрального анализа этих данных алгоритмом быстрого преобразования фурье, либо поднимать Астериск и скриптовать там. Второй путь был отвергнут сразу, ибо это всё равно что электронным микроскопом забивать гвозди. Остановился на первом варианте, в результате родился эдакий быдлокод, который с довольно высокой вероятностью определяет момент поднятия трубки.

            ExpandedWrap disabled
              #!/usr/bin/perl -w
               
              use Math::FFT;
              use Time::HiRes;
              use Device::SerialPort;
              use strict;
              use Switch;
              use warnings;
              use List::MoreUtils qw(firstidx);
               
              my %notes = ( 255 => 'Vmin', 275 => 'V1', 300 => 'V2', 325 => 'V3', 350 => 'V4', 375 => 'Vmax', 425 => 'A', 1000 => 'B');
               
              my @freqs = sort { $a <=> $b } keys %notes;
               
              use constant DLE        => 0x10;
              use constant ESC        => 0x1B;
               
              use constant MAX_TIME_VAD               => 50; #sec
              use constant BYTES_FOR_FFT              => 4096;
               
              my $DLE_DETECT          = chr(DLE);
              my $DLE_BUSY            = chr(0x62);
              my $CONNECT             = "CONNECT\r\n";
               
              my $port = '/dev/ttyS0';
               
              my $number = '1234567'; #Номер куда звоним
               
                my $hDevice = new Device::SerialPort($port) or die "Can't open port $port: $!\n";
                my @handshake_opts = $hDevice->handshake;
                my $can_set_rts = 0;
                foreach (@handshake_opts) {
                  if ($_ eq 'rts') {
                    $can_set_rts = 1;
                    last;
                  }
                }
                die "Cannot set handshake 'rts' to port $port" if ($can_set_rts == 0);
                $hDevice->buffers(BYTES_FOR_FFT, BYTES_FOR_FFT);
                $hDevice->baudrate(115200);
                $hDevice->parity('none');
                $hDevice->databits(8);
                $hDevice->stopbits(1);
                $hDevice->handshake('rts');
                $hDevice->read_const_time(150);
                $hDevice->write_settings;
               
                send_cmd($hDevice, 'ATZ');
                send_cmd($hDevice, 'ATS7=50');
                send_cmd($hDevice, 'AT+FCLASS=8;+FLO=2');
                send_cmd($hDevice, 'AT+VRN=0;+VTD=10;+VIT=0');
                send_cmd($hDevice, 'AT+VGR=128');
                send_cmd($hDevice, 'AT+VSM=128,8000,0,0');
                my ($prev, $dle, $code, $pos);
                my $state = -1;
                my $start = 1;
                if (send_cmd($hDevice, "ATDT $number") =~ /OK/) {
                  $hDevice->write('AT+VRX' . "\r");
                  $hDevice->lookclear;
                  $buff = '';
                  my $time_start = time;
                  my $counter = 0;
                  while(1) {
                    my ($count,$raw) = $hDevice->read(BYTES_FOR_FFT);
                    if($count > 0) {
                      if (($raw =~ /$CONNECT/) && ($start == 1)) {
                          $pos   = $+[0];
                          $raw   = substr($raw, $pos);
                          $start = 0;
                      }
                      $state = 0 if ($raw =~ /[^$DLE_DETECT][$DLE_DETECT][$DLE_BUSY]/);
                      last if ((time-$time_start > MAX_TIME_VAD) || ($state >= 0));
                      $raw =~ s/[$DLE_DETECT][$DLE_DETECT]/[$DLE_DETECT/g;
                      $buff .= $raw;
                      if (length($buff) >= BYTES_FOR_FFT) {
                        switch (detect_ring_back_tone(substr($buff, 0, BYTES_FOR_FFT))) {
                          case 0 { $counter = 0; }
                          case 1 { $counter = 10; }
                        }
                        $buff = substr($buff, BYTES_FOR_FFT);
                        $counter++;
                        $state = 1 if ($counter > 10);
                      }
                    }
                  }
                  $hDevice->write(chr(ESC));
                  if ($state == 1)  {
                    #ВОТ ЗДЕСЬ МЫ БУДЕМ КОГДА ТРУБКА БУДЕТ ПОДНЯТА
                  }
                }
                send_cmd($hDevice, 'ATH');
                send_cmd($hDevice, 'ATZ');
               
                undef $hDevice;
              }
               
              sub send_cmd {
                my ($hDev, $cmd, $no_with_CRLF, $no_wait) = @_;
                my $result = '';
                $cmd .= "\r" unless (defined($no_with_CRLF));
                $hDev->lookclear;
                $hDev->write($cmd);
                return 0 if (defined($no_wait));
                while(1) {
                  my ($count,$saw) = $hDev->read(4096);
                  if($count > 0) {
                    $result .= $saw;
                    last if (($saw =~ /OK/) or ($saw =~/ERROR/) or ($saw =~ /DIALTONE/) or ($saw =~ /CONNECT/));
                  }
                }
                return $result;
              }
               
              sub detect_ring_back_tone {
                my ($data, $x) = @_;
                my $fft = Math::FFT->new( [ unpack( 's<*', substr $data, 0, BYTES_FOR_FFT, '' ) ] );
                my $spectrum = $fft->spctrm();
                my ( $min, $max ) = $fft->range($spectrum);
                my $f = firstidx { $_ >= $max } @$spectrum;
                my $result = 0;
                return -1 unless $f;
                while ( $f < $freqs[0] ) { $f *= 2; }
                while ( $f > $freqs[-1] ) { $f /= 2; }
                for ( my $i = 1 ; $i < @freqs ; $i++ ) {
                  if ( $f <= $freqs[$i] ) {
                    my $index = $i;
                    $index-- if ( $freqs[$i] - $f > $f - $freqs[ $i - 1 ] );
                    my $ampl = ( $f - $freqs[$index] ) / ( $freqs[$i] - $freqs[ $i - 1 ] );
                    $result = 0 if ($freqs[$index] == 425);
                    $result = 1 if (($freqs[$index] >= 255) && ($freqs[$index] <= 400));
                    last;
                  }
                }
                return $result;
              }

            Цитата
            У меня другой вопрос: как скормить wav модему? Этот вопрос тоже периодически всплывает и внятного ответа раз и навсегда пока не было.

            Элементарно, подгототавливаем wav в PCM, 8кГц, 8бит, моно, в буфер $buff_wav данные из файла без заголовка WAV в 44 байта, затем
            ExpandedWrap disabled
              send_cmd($hDevice, 'AT+FCLASS=8');
              send_cmd($hDevice, 'AT+VGT=128');
              send_cmd($hDevice, 'AT+VSM=132,8000,0,0'); #Pltcm
              send_cmd($hDevice, 'AT+VTX');
              $hDevice->write($buff_wav) if (length($buff_wav) > 0);
              send_cmd($hDev, chr(DLE) . chr(3), 1, 1);


            Добавлено
            Цитата Prince @
            На сигнал КПВ(1 раз в 5 секунд) модем выдаёт комбинации из двух байт: <DLE>b. DLE=char($10).

            Нет, <DLE>+b, это DCE посылает сигнал занятости линии на том конце, когда мы набрали номер. КПВ никак не сигнализируется. Проверено.

            Добавлено
            Цитата Gonarh @
            Тогда другой вопрос: каким образом это делают программы подобные
            VentaFax'у (кстати она тоже писана на дельфи)

            Отвечу сам себе :lol: Именно алгоритмом FFT.
            Сообщение отредактировано: Gonarh -
            1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
            0 пользователей:


            [ Script Execution time: 0,0993 ]   [ 15 queries used ]   [ Generated: 29.03.17, 18:55 GMT ]