Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[18.119.131.178] |
|
Сообщ.
#1
,
|
|
|
Искал в поиске,гуглил, с периодичностью раз в 2-3 месяца данный вопрос
проскальзывает и на нашем форуме, везде практически один и тотже ответ: "никак или чрезвычайно сложно". Нигде нет даже приблизительной реализации Тогда другой вопрос: каким образом это делают программы подобные VentaFax'у (кстати она тоже писана на дельфи) |
Сообщ.
#2
,
|
|
|
Цитата Mr. Gonarh @ Тогда другой вопрос: каким образом это делают программы подобные VentaFax'у (кстати она тоже писана на дельфи) Ожидают пилотного тона факса приемной стороны. |
Сообщ.
#3
,
|
|
|
Цитата Ожидают пилотного тона факса приемной стороны. для тех кто в танке: что такое пилотный тон факса кроме того какой может быть пилотный тон факса, если трубку снимает человек, VentaFax ловит это и начинает транслировать WAV файл в линию |
Сообщ.
#4
,
|
|
|
Через 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 работает криво). |
Сообщ.
#5
,
|
|
|
Обалдеть. Почти 10 лет прошло. В общем так. Пару недель назад опять пришлось столкнуться с задачей определения поднятия трубки. Пошукав по интернетам, перелопатив довольно таки огромное количество топиков на десятках различных форумах(на этот топик тоже через поиск наткнулся ), понял что единственный высоковероятностный метод определения поднятия трубки, это запись данных телефонной линии после набора номера, и спектрального анализа этих данных алгоритмом быстрого преобразования фурье, либо поднимать Астериск и скриптовать там. Второй путь был отвергнут сразу, ибо это всё равно что электронным микроскопом забивать гвозди. Остановился на первом варианте, в результате родился эдакий быдлокод, который с довольно высокой вероятностью определяет момент поднятия трубки.
#!/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 байта, затем 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'у (кстати она тоже писана на дельфи) Отвечу сам себе Именно алгоритмом FFT. |