|
Запуск Linux Skype 4.0.0.8 под управлением FreeBSD (доп. ссылка 1) |
[комментарии]
|
| Как известно порт net/skype уже несколько лет не обновлялся, а предлагаемая
в порте версия Skype 2.1 не позволяет совершать видеовызовы клиентов,
пользующихся новыми выпусками Skype для Windows. В списке рассылки freebsd-emulation
опубликована
инструкция по запуску Linux-версии Skype 4.0.0.8 во FreeBSD.
Устанавливаем следующие Linux-библиотеки, которые можно найти в составе порта emulators/linux_base-c6:
lib/ld-2.12.so
lib/ld-linux.so.2
lib/libgcc_s-4.4.6-20110824.so.1
lib/libgcc_s.so.1
lib/libdl-2.12.so
lib/libdl.so.2
lib/libglib-2.0.so.0
lib/libglib-2.0.so.0.2200.5
lib/libc-2.12.so
lib/libc.so.6
lib/libpthread-2.12.so
lib/libpthread.so.0
usr/lib/libstdc++.so.6
usr/lib/libstdc++.so.6.0.13
В makefile порта emulators/linux_base-c6 комментируем строку:
CONFLICTS=linux_base-gentoo* linux_base-f* linux-glib2-*
и выполняем
make patch
После этого копируем собранные библиотеки в /compat/linux
Ставим символическую ссылку libtiff.so.3 на libtiff.so.4.
Замена библиотек, вместо установки порта emulators/linux_base-c6, необходима
для сохранения совместимости с linux-f10-flashplugin. Если потребности в
запуске Flash нет, можно просто установить порт emulators/linux_base-c6 без
ручного копирования.
Устанавливаем переменную compat.linux.osrelease в 2.6.18:
sysctl compat.linux.osrelease=2.6.18
Для обеспечения поддержки видеовызовов заменяем в коде ядра FreeBSD
заголовочный файл linux_videodev2.h, скопировав новый вариант из порта multimedia/linux_v4l2wrapper-kmod:
cd /usr/ports/multimedia/linux_v4l2wrapper-kmod
make patch
mv -i /sys/compat/linux/linux_videodev2.h{,.bak}
cp -i work/linux_v4l2/linux_videodev2.h /sys/compat/linux
После этого пересобираем ядро FreeBSD.
|
|
|
|
|
Набор номера на Cisco IP Phone 7960/7940 из скрипта |
Автор: Alex Samorukov
[комментарии]
|
| Решил поделиться скриптом для набора номера на аппаратах Cisco IP Phone
7960/7940 (возможно, работает и на других с аналогичной прошивкой). Зачем это
может быть нужно? Я это использую для интеграции с callto:// links и
интеграцией со своим телефонным справочником. Скрипт работает через telnet, так
что вы должны включить его на телефоне. Набор номера использует команду test,
которая служит для эмуляции нажатия кнопок на аппарате. Пауза (с зависимостью
от длинны номера) требуется для того, чтобы телефон не сходил с ума.
Надеюсь, кому-то это скрипт тоже пригодится.
#!/usr/bin/perl
use Net::Telnet;
use Time::HiRes;
# cisco phone host name
my $host='192.168.0.1';
# cisco phone password
my $password='cisco';
# mute on a dial 0/1
my $mute=0;
my $sleeptime=.2;
my $prompt='/> $/';
my $argc = @ARGV;
if ($argc!=1){
print "Usage: call.pl <number>\\n";
exit;
}
my $number=@ARGV[0];
if($number!~/^[0-9*#]+$/) {
print "Error: wrong characters in the numer\\n";
exit 2;
}
$telnet = new Net::Telnet ( Timeout=>3, Errmode=>'die');
# connecting
$telnet->open($host);
$telnet->waitfor('/Password :$/i');
$telnet->print($password);
$telnet->waitfor($prompt);
$telnet->print('test open');
$telnet->waitfor($prompt);
$telnet->print('test key spkr');
$telnet->waitfor($prompt);Time::HiRes::sleep($sleeptime);
if($mute){
$telnet->print('test key mute');
$telnet->waitfor($prompt);Time::HiRes::sleep($sleeptime);
}
$telnet->print("test key ".$number."#");
$telnet->waitfor($prompt);Time::HiRes::sleep((length($number)+1)*$sleeptime);
$telnet->print('test close');
$telnet->waitfor($prompt);
$telnet->close($host);
|
|
|
|
|
Телефонная книга Asterisk для eyeBeam 1.x |
Автор: desenix
[комментарии]
|
| Итак, есть Asterisk (использовался 1.10 beta) и программный VoIP-телефон
eyeBeam 1.x, связь с книгой соответственно осуществляется через WebDav. Для
eyeBeam 1.5.x не подходит, так как другой формат записей и сохранять через
WebDav он не умеет (видимо писала другая команда).
Настройки софтфона:
Server-side Storage:
Storage method: WebDAV
Use SIP credentials: +
Root URL: http://webdav.example.local/webdav/
WebDAV pool time: 600
Так как все пользователи будут в одном каталоге, их файлы имеют разные имена,
теоретически возможна порча одним пользователем, файла телефонной книги другого.
Ещё нам понадобиться Apache с модулем WebDAV, его конфигурация:
<VirtualHost *:80>
ServerName webdav.example.local
ServerAdmin [email protected]
DocumentRoot /server/www/WEBDAV
ErrorLog "/server/www/WEBDAV/error.log"
<Directory /server/www/WEBDAV/>
AllowOverride None
Order deny,allow
deny from all
</Directory >
<Directory /server/www/WEBDAV/webdav/>
Options Indexes MultiViews
AllowOverride None
Order allow,deny
allow from all
</Directory>
DavLockDB /server/www/WEBDAV/DavLock
<Location /webdav/>
DAV on
AuthType Basic
AuthName "WebDav"
AuthUserFile /server/www/WEBDAV/paswd
Require valid-user
</Location>
</VirtualHost>
Создаём директорию /server/www/WEBDAV/webdav/ или в другом месте по желанию,
назначаем владельцем пользователя из под которого работает Apache. Файл паролей
создавать не надо, его создаст скрипт, о котором далее.
Создаём там где удобно файл phonebook.pl, его необходимо запускать после
добавления/удаления пользователя из Asterisk, как это сделать автоматически не
нашёл, поэтому запускаю руками.
Скрипт написан немного коряво, так как пишу на Perl время от времени и по справочникам.
#!/usr/bin/perl
use POSIX;
# путь к файлу пользователей Asterisk (должен существовать)
$srccfg="/etc/asterisk/users.conf";
# путь к файлу паролей webdav (создаётся автоматически, перезаписывается)
$paswdfile="/server/www/WEBDAV/paswd";
# путь к файлам профилей с телефонными книгами пользователей (создаётся автоматически, перезаписывается)
$phbookfiles="/server/www/WEBDAV/webdav";
# домен SIP, используется при генерации телефонных книг
$sipdomain="example.local";
# суффикс телефонной книги eyeBeam в формате XML, для webdav (константа, не менять!)
$phbooksuf="resource-list.xml";
# суффикс для файла с правилами (константа, не менять!)
$phrulesuf="presence-rules.xml";
# путь для временных файлов
$tmpath="/var/tmp";
# владелец файлов, от которого выполняется Apache ( автоматически
# назначается создаваемым файлам телефонной книги и файлу паролей )
$apacheuser="apache.apache";
# приложение для генерации файла паролей.
$htpasswd="htpasswd";
open(SF, "$srccfg") || die;
$flag=0;
@number=();
@name=();
@pasw=();
$cnt=0;
$phonetext="";
while ($line = <SF>)
{
$st = $line=~s/^\[(.*)\].*[\n\r]*/\1/g;
if($st) {
$flag=1;
$number[$cnt]=$line;
}
$st = $line=~s/^fullname\s*=\s*([^\n\r]*)\s.*/\1/g;
if($st && $flag) {
$name[$cnt]=$line;
$flag=$flag+1;
$st = $number[$cnt]=~m/general/g;
if($st) { $flag=0; }
}
$st = $line=~s/^secret\s*=\s*([^\n\r]*)\s.*/\1/g;
if($st && $flag) {
$pasw[$cnt]=$line;
$flag=$flag+1;
}
if($flag>=3){
$flag=0;
$phonetext = $phonetext." \\r\n\ ".$name[$cnt]."\\r \n\ \r\n";
#print("\\ n\r\".$name[$cnt]."\\n\r\\n\r");
#print "pasword=$pasw[$cnt]\r\n";
if($cnt==0){ system $htpasswd, "-bc", $paswdfile, $number[$cnt], $pasw[$cnt]; }
else{ system $htpasswd, "-b", $paswdfile, $number[$cnt], $pasw[$cnt]; }
$cnt=$cnt+1;
}
}
close(SF);
# chown
system "chown", $apacheuser, $paswdfile;
$phonemask1="\<display\-name\>PhoneBook\<\/display\-name\>\r\n";
$phonemask2="\<\/list\>";
$phonemask = '\<display\-name\>PhoneBook\<\/display\-name\>.*?\<\/list\>';
$cntt=0;
while($cntt<$cnt){
$fphbook=$phbookfiles."/".$number[$cntt].".". $sipdomain.".".$phbooksuf;
$fphrule=$phbookfiles."/".$number[$cntt].".". $sipdomain.".".$phrulesuf;
$cntt=$cntt+1;
if( -e $fphbook){ print "Update: $fphbook\r\n";
open(SF, "$fphbook") || die "Can't open file read $fphbook";
@var = <SF>;
close(SF);
$var = join('',@var);
$st = $var =~ s/\<display\-name\>PhoneBook\<\/display\-name\>.+?<\/list>/$phonemask1$phonetext$phonemask2/si;
print "RES:$st\r\n";
if($st) {
system "chmod", "666",$fphbook;
open(SF, ">$fphbook") || die "Can't open file write $fphbook";
print SF $var;
close(SF);
system "chmod", "644",$fphbook;
}#if
}else{ # файл не существует, создадим его
print "Create: $fphbook\r\n";
open(SF, ">$fphbook") || die;
print SF "\\r\n";
print SF "\\r\n";
print SF " \\r\n";
print SF " \PhoneBook\\r\n";
print SF "$phonetext";
print SF " \\r\n";
print SF " \\r\n";
print SF " \Private\\r\n";
print SF " \\r\n";
print SF " \\r\n";
print SF " \Choose\\r\n";
print SF " \\r\n";
print SF "\\r\n";
close(SF);
# chown
system "chown", $apacheuser, $fphbook;
}
if( ! -e $fphrule){
print "Create: $fphrule\r\n";
open(SF, ">$fphrule") || die;
print SF "\\r\n";
print SF "\\r\n";
print SF "\\r\n";
close(SF);
# chown
system "chown", $apacheuser, $fphrule;
}
#print "$fphbook\r\n";
}#while
Нюансы:
1. Для данного софтфона, книга подгружается и сохраняется сама, по указанному таймауту.
2. В справочнике появляется группа PhoneBook, в ней контакты Asterisk, если
туда добавить что-то из софтфона, при следующем обновлении будет затёрто.
Поэтому для иных контактов можно создавать другие группы (прямо в софтфоне) и в
них добавлять свои контакты. Так для этого специально скриптом создаётся пустая
группа Personal.
PS: Желающие могут доработать скрипт, например создать отдельно группы
конференций, служебную (голосовая почта и т.п.)
|
|
|
|
|
Донабор номера по одной цифре и организация гудка после 8/9 в Asterisk (доп. ссылка 1) |
Автор: Alex/AT
[комментарии]
|
| Нижеизложенный пример конфигурации Asterisk позволяет обеспечить вывод гудка
после набора "8" или "9", как на городском телефоне, и решить проблему со
временем ожидания вызова (некоторые пользователи не успевают набрать номер, но
если увеличить задержку, другие жалуются на излишне долгий вызов) через
организацию донабора номера по одной цифре.
[upats]
; номера "УПАТС"
exten => 100,1,Dial(SIP/Local100,,tT)
exten => 100,n,Congestion()
exten => 100,n,Hangup()
exten => 101,1,Dial(SIP/Local101,,tT)
exten => 101,n,Congestion()
exten => 101,n,Hangup()
; экстренные службы
exten => _0[1-4]!,1,Dial(SIP/external/${EXTEN})
exten => _0[1-4]!,n,Congestion()
exten => _0[1-4]!,n,Hangup()
exten => _112!,1,Dial(SIP/external/${EXTEN})
exten => _112!,n,Congestion()
exten => _112!,n,Hangup()
exten => _911!,1,Dial(SIP/external/${EXTEN})
exten => _911!,n,Congestion()
exten => _911!,n,Hangup()
; набор номера между странами через "810", к сожалению, длина номера произвольная :(,
; и решение на эти номера не сработает - номер придется набирать быстро;
; выход во внешний мир - через "8" на внешнем операторе
exten => _810X!,1,Dial(SIP/external/8${EXTEN:1},,tT)
exten => _810X!,n,Congestion()
exten => _810X!,n,Hangup()
; набор номера через "8", выход во внешний мир - через "8" на внешнем операторе
exten => _8NXXXXXXXXX!,1,Dial(SIP/external/8${EXTEN:1},,tT)
exten => _8NXXXXXXXXX!,n,Congestion()
exten => _8NXXXXXXXXX!,n,Hangup()
; набор городского номера через "9", выход на городские номера прямой на внешнем операторе
exten => _9NXXXXXX!,1,Dial(SIP/external/${EXTEN:1},,tT)
exten => _9NXXXXXX!,n,Congestion()
exten => _9NXXXXXX!,n,Hangup()
; обработка донабора в случае, если абонент ничего вменяемого не набрал
exten => _X!,1,Set(X_PREDIGITS=${EXTEN})
exten => _X!,n,Set(X_ORIGCONTEXT=${CONTEXT})
exten => _X!,n,Set(X_REPEATS=1)
exten => _X!,n,Goto(more,s,1)
; а сюда подаем в случае полной засады
exten => i,1,Congestion()
exten => i,n,Hangup()
; а это, собственно, процедура донабора
[more]
; проверка прогресса вызова
exten => s,1,GotoIf($["${X_PROGRESS}" = "1"]?tone)
exten => s,n,Set(X_PROGRESS=1)
exten => s,n,Answer()
exten => s,n(tone),GotoIf($["${X_TONE}" = "2"]?wait)
exten => s,n,GotoIf($["${X_TONE}" = "1"]?check)
; нужно проиграть гудок?
exten => s,n,GotoIf($[${LEN(${X_PREDIGITS})} > 1]?setstop)
exten => s,n,GotoIf($[$["${X_PREDIGITS:0:1}" != "9"] & $["${X_PREDIGITS:0:1}" != "8"]]?setstop)
; проигрываем гудок после "8", "9"
exten => s,n,PlayTones(425/1000)
exten => s,n,Set(X_TONE=1)
exten => s,n,Goto(wait)
; нужен ли еще гудок?
exten => s,n(check),GotoIf($[${LEN(${X_PREDIGITS})} > 1]?stop)
exten => s,n,Goto(wait)
; прекращаем гудеть
exten => s,n(stop),StopPlayTones()
exten => s,n(setstop),Set(X_TONE=2)
exten => s,n,Goto(wait)
; ждем цифру (5 - интервал, который ждем перед выходом)
exten => s,n(wait),WaitExten(5)
exten => _X!,1,Goto(${X_ORIGCONTEXT},${X_PREDIGITS}${EXTEN},1)
exten => t,1,Set(X_REPEATS=$[${X_REPEATS}-1])
; не успели?
exten => t,n,GotoIf($[${X_REPEATS} >= 0]?i,1)
exten => t,n,Goto(s,1)
; сброс линии если не успели
exten => i,1,Congestion()
exten => i,n,Hangup()
|
|
|
|
|
Решение проблемы с крахом Linux-клиента Skype (доп. ссылка 1) |
[комментарии]
|
| Сегодня многие пользователи Skype отметили падение Skype-клиента для Linux
при попытке соединения, с последующей невозможностью его повторного запуска.
Представители Skype признали наличие проблемы и обещали оперативно её устранить.
Эмпирическим путем было выявлено, что проблему можно решить удалив файл
shared.xml в служебной директории Skype.
Для решения проблемы достаточно выполнить:
mv ~/.Skype/shared.xml ~/.Skype/shared~.xml
|
|
|
|
|
VoIP-звонки из web-браузера с использованием siprtmp |
Автор: Александр
[комментарии]
|
| Столкнулся с необходимостью внедрить sip-телефон в браузер. На просторах
Интернета больше всего рассказывают о решении на базе red5 и red5phone,
но оно мне показался слегка монструозным и недостаточно надежным. Скажем так,
меня не устроило соотношение времени развертывания и требуемых аппаратных
ресурсов к уровню качества, беспроблемности поддерживания и масштабируемости. К
тому же наблюдались проблемы при интеграции в веб-проект.
Еще немного поискав в Интернете нашел проект siprtmp. Делает по сути то же
что и red5, но написан на python и имеет гибкий веб-интерфейс.
По сути веб-интерфейс siprtmp - это небольшое приложение на флеш, управляемое с
помощью JavaScript или другого языка программирования, посредством вызова
встроенных функций приложения и обработки событий. Имеет возможность
встраиваться в другие флеш-приложения.
Запуск сервера производится такими манипуляциями:
svn checkout http://p2p-sip.googlecode.com/svn/trunk/ p2p-sip-read-only
svn checkout http://rtmplite.googlecode.com/svn/trunk/ rtmplite-read-only
cd ./rtmplite-read-only
PYTHONPATH=../p2p-sip-read-only/src:.
export PYTHONPATH
python ./siprtmp.py
Может понадобиться указать IP-адрес, который будет указываться при общении с
вашей ip-pbx, это можно сделать при помощи ключа "-е ip". Для отладки есть ключ -d.
В данной версии велика вероятность проявления ошибки, при которой будет
невозможно совершать исходящие звонки. Лечится при помощи добавления
комментария на строку 217 в файле p2p-sip-read-only/src/std/rfc3261.py. Данная
ошибка скоро со слов разработчика скоро будет устранена.
При настройке sip-сервера для работы с siprtmp, пользователям, которые будут
звонить через веб, необходимо разрешить использовать только кодек speex,
например в Asterisk это делается так:
disallow = all
allow = speex
На сайте разработчика можно найти пример телефона и подробное описание.
Думаю значение полей понятно и без описания. Также данное решение может
использоваться для видео-звонков и конференций. Главное не забудьте разрешить
флеш-приложению использовать аудио устройства вашего компьютера.
Официальная страница сервера: http://code.google.com/p/siprtmp/
Официальная страница флеш-клиента: http://code.google.com/p/flash-videoio/
Еще одна страница флеш-клиента: http://myprojectguide.org/p/flash-videoio/
В данный момент совместно с разработчиком проекта осуществляются попытки
создать полноценный демон из siprtmp.py и побороть необходимость выполнения
"export PYTHONPATH=../p2p-sip-read-only/src:.".
|
|
|
|
|
Организация прямого SIP-соединения компьютеров при помощи GNU SIP Witch (доп. ссылка 1) |
[комментарии]
|
| Проект GNU SIP Witch позволяет напрямую связать несколько компьютеров,
предоставив возможность прямой отправки и приёма SIP-звонков через интернет,
без использования внешних SIP-сервисов и шлюзов, а также давая возможность
соединения машин, доступ в сеть которых организован через транслятор адресов
(NAT). Выступая в роли посредника, GNU SIP Witch может быть установлен как на
локальной машине, на которой запускается SIP-клиент, так и на сервере, позволяя
обеспечить работу сразу для нескольких машин в локальной сети. Все операции
обработки и кодирования медиапотоков осуществляются на стороне SIP-клиента, GNU
SIP Witch занимается лишь согласованием SIP-соединений, обеспечивает простейшие
операции проброса канала связи до абонента и маршрутизации вызовов по
URI-идентификаторам абонентов, что делает программу легковесной и не
требовательной к ресурсам.
Рассмотрим процесс установки и настройки GNU SIP Witch в Ubuntu Linux для
организации прямых звонков через интернет, используя такие SIP-клиенты, как
Twinkle Softphone и SIP Communicator.
Установим GNU SIP Witch, который присутствует в стандартном репозитории Ubuntu и Debian:
sudo apt-get install sipwitch sipwitch-plugin-forward
автоматически в систему будут установлены библиотеки libexosip2-4, libosip2-4,
libsipwitch0 и libucommon2.
Конфигурация сервера:
Активируем в настройках плагин forward, если планируем задействовать функции
для перенаправления соединений для Asterisk или FreeSwitch. В
/etc/default/sipwitch заменяем
PLUGINS="none"
на
PLUGINS="forward"
или PLUGINS="auto" для загрузки всех доступных плагинов.
Добавляем себя в группу sipwitch:
sudo usermod -aG sipwitch myname
Настройка регистратора SIP Witch
Основная конфигурация SIP Witch находится в файле /etc/sipwitch.conf, в котором
описны настройки SIP-стека, план нумерации абонентов и маршрутизация.
Наиболее важные настройки в блоке <registry>:
<prefix> - задает дополнительный префикс локальной нумерации абонентов.
Рассмотрим пример присвоения абонентам трехзначных номеров из диапазона
100-699. Блок <range> определяет диапазон доступных номеров. Блок <mapped>
задает максимальное число пользовательских агентов, которые могут быть
зарегистрированы на сервере.
<prefix>100</prefix>
<range>600</range>
<mapped>700</mapped>
Если сервер планируется использовать для осуществления звонков в другие
SIP-сети, например через задействование Asterisk или FreeSwitch, то следует
указать параметр <realm>, который определит уникальный идентификатор сервера.
Для осуществления вызова абонентов Asterisk в качестве realm нужно прописать
значение, указанное в конфигурации sip.conf Asterisk-сервера, например:
<realm>Asterisk</realm>
иначе, можно указать любой другой идентификатор.
Настройка SIP-стека
Рассмотрим блок <stack> в файле /etc/sipwitch.conf, в котором определяются
такие параметры как сетевой интерфейс и номер порта для привязки. Большинство
настроек можно оставить по умолчанию, обратить внимание стоит на параметры
<mapped> и <localnames>.
В <mapped> задается марсимальное число одновременных телефонных вызовов,
которое sipwitch может обработать. При превышении данного лимита попытки
подключения приведут к выводу сигнала "занято". Для обеспечения возможности
одновременной работы всех абонентов, с учетом того, что в каждом локальном
вызове фигурирует два локальных номера, значение <mapped> можно установить как
половину от величины <mapped> из секции <registry>.
В <localnames> задаются поддерживаемые имена хостов (аналогичные тем, что
указаны в настройке "domain" VoIP-клиента twinkle), по умолчанию принимаются
все имена.
Например:
<localnames>sip.test.ru, server.local</localnames>
Для ограничения доступа к серверу только абонентов локальной сети, следует указать:
<restricted>local</restricted>
<trusted>local</trusted>
Список локальных подсетей можно указать в блоке <access>, например:
<access>
<local>172.16.59.0/24</local>
</access>
Настройка маршрутизации в SIP Witch
SIP Witch может использоваться для установки на несколько узлов, позволяя
построить большую сеть, каждый сервер в которой обслуживает абонентов со своей
нумерацией (например, можно соединить территориально разнесенные офисы предприятия).
Указание информации о дополнительных серверах и задание правил перераправления
вызовов производится в секции <routing>.
Например, для перенаправления обращений по номерам с 200 по 299 на другой
SIP-сервер с именем server2.local можно использовать следующее правило:
<routing>
<redirect pattern="2xx" server="server2.local"/>
</routing>
Для перенаправления обращений к номерам "3xx" на удаленный сервер можно использовать правило:
<redirect pattern="3xx" target="sip:[email protected]"/>
Резервирование номеров для заданных пользователей
Для привязки номеров к абонентам и определения их параметров в директории
/etc/sipwitch.d следует создать файл c описанием абонентов. В простейшем виде
создадим /etc/sipwitch.d/test.xml в котором заведем несколько номеров:
<provision>
<user id="логин1">
<secret>пароль</secret>
<extension>101</extension>
<display>Отображаемое имя абонента 1</display>
</user>
<user id="логин2">
<digest>хэш пароля</digest>
<extension>102</extension>
<display>Отображаемое имя абонента 2</display>
</user>
</provision>
В поле id указывается логический идентификатор пользователя, например можно
указать логин или email. В поле secret/digest задается пароль/хэш для доступа.
В поле extension указывается телефонный номер абонента. В поле display
указывается имя которое будет отображаться при звонке. Перенаправление вызова
можно указать через блок <forward>.
Для формирования хэша пароля можно использовать утилиту (-realm можно не
указывать, тогда будет использован realm текущего сервера):
sipdigest -realm Реалм_сервера логин пароль
Управление сервисом SIP Witch
Запускаем sipwitch:
sudo /etc/init.d/sipwitch start
Для управления сервисом нужно использовать команду sipwitch, например:
Вывод списка активных звонков:
sipwitch calls
Список зарегистрировавшихся клиентов:
sipwitch registry
Статус работы:
sipwitch status
Статистика по обслуживаемым звонкам:
sipwitch stats
Применение изменений в файлах конфигурации:
sipwitch reload
Логи
В процессе работы создается три основных лога:
/var/log/sipwitch.log - лог для ошибок и системных событий
/var/log/sipwitch.stats - почасовая статистика звонков
/var/log/sipwitch.calls - полный список всех звонков
Для ротации логов в систему установлен файл /var/logrotate.d/sipwitch
Для формирования почасовой статистики используется скрипт /etc/cron.hourly/sipwitch
Подключение SIP-клиентов
Для осуществления звонков подойдет любой SIP-совместимый клиент, для примера настроим Twinkle:
sudo apt-get install twinkle
В процессе заполнения профиля, указываем приведенный в секции <user id="xxx">
идентификатор (логин) в поле имени пользователя и имени аутентификации, в поле
домена вводим sip.test.ru или server.local, в поле realm указываем содержимое
поля <realm> (в нашем случае Asterisk). Во вкладке "безопасность" включаем
шифрование ZRTP/SRTP.
Соединяемся и проверяем:
sipwitch registry
ext user type profile use expires address
101 test1 user * 0 3580 127.0.0.1:5061
found 1 entries active of 600
|
|
|
|
|
Русскоговорящий будильник/напоминаловка для Asterisk (доп. ссылка 1) |
Автор: cr80
[комментарии]
|
| В Asterisk есть штатный будильник - напоминаловка, если вы загляните в
директорию /var/lib/asterisk/agi-bin, то увидите что-то похожее на wakeup.php.
Вещь не плохая, но хочу предложить Вашему вниманию, более продвинутую версию
русскоговорящего будильника. В нашем случае, Вы можете отправлять голосовые
сообщения как сами себе, так и на любые другие номера. Причем задавать дату
можно как в четком виде ГГММДД ЧЧММ, так и в неявном виде, через 10 минут от
текущего времени, или через 3-и дня от текущей даты.
Концепция будильника следующая, пользователь вводит со своего телефона
комбинацию цифр вида *0*X*Y*Z, где
X - дата, когда необходимо озвучить сообщение
Y - время, когда необходимо озвучить сообщение
Z - номер, на который необходимо позвонить для проигрывания сообщения
Возможные варианты значения X (дата, когда проигрывать напоминание)
0 - Звонить сегодня
От 1 до 99 - Позвонить через 1-99 дней
ГГГГММДД - Позвонить в конкретную дату
Возможные варианты значения Y (время, когда проигрывать напоминание)
0 - Звонить в это время (не работает с текущим днем)
От 1 до 999 - Звонить через 1-999 минут
ЧЧММ - Звонить в конкретное время
Возможные варианты значения Z (номер куда будем отправлять напоминание)
0 - Номер с которого звонят
zzz -Локальный номер (у меня 3-значные номера)
zzzzzzzzzzzzzzzzz - Внешний номер, может быть любым!
Примеры:
*0*0*120*0 - позвонить через 2-а часа на свой телефон, и озвучить
надиктованное сообщение (не забыть выключить суп!).
*0*20101231*2300*777 - позвонить 31 декабря 2010 года в 23.00 на номер 777 и
озвучить поздравление с новым годом!
*0*30*1500*78123090607 - позвонить через 30 дней в 15.00 на номер 78123090607
и озвучить сообщение (пора оплачивать счета)!
*0*20110308*0*1234567 - позвонить 8 марта 2011 года в текущее время на номер
1234567 и озвучить поздравление с праздником!
Думаю, концепция ввода даты, времени и номера, куда необходимо позвонить для
напоминания вам ясна. Теперь перейдем к технической реализации нашей задачи.
В файле extensions.conf мы должны описать наш экстеншен!
exten => _*0*X.,1,Answer
exten => _*0*X.,n,AGI(reminder.agi)
exten => _*0*X.,n,Hangup
Таким образом, все набранные номера, которые начинаются с *0* попадают в наш
контекст и включают скрипт reminder.agi
Далее опишем контекст go - он запускается call файлом в момент когда происходит
дозвон до абонента с целью озвучить надиктованное сообщение.
exten => go,1,NoOp("Будильничег")
exten => go,n,AGI(reminder_listen.agi)
exten => go,n,HagnUp
ну и теперь самое интересное, это наши скрипты
/var/lib/asterisk/agi-bin/reminder.agi
#!/usr/bin/perl
use Asterisk::AGI;
use POSIX;
use File::Copy;
use Time::Local;
use Date::Calc qw (Add_Delta_Days);
$AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
$trunk="megatrank";
# начало отсчета с 1900 года, значение year - смещение от 1900 года
$datesec=time;
#chomp($datesec);
# получаем значение exten и заносим в переменную $digit -
# это то что набрал пользователь на своем телефоне, далее мы
# разберем по частям эти цифры с целью понять что хотел сказать
# пользователь (когда и куда звонить)
$digit = $AGI->get_variable('EXTEN');
# на всякий случай, выдергиваем номер звонящего
$src = $AGI->get_variable('CALLERID(num)');
#регулярным выражением выдергиваем значения даты времени и номера звонящего
$digit =~ /^\*0\*(\d+)\*(\d+)\*(\d+)/;
$wdate=$1;
$wtime=$2;
$wnum=$3;
# вводим маленькую функцию для озвучки ошибки набора, что бы
# несколько раз не писать один и тот же код!
# обратите внимание, я взял звуковые файлы с http://ivrvoice.ru/downloader
# и перекинул их в Asterisk в папку /var/lib/asterisk/sounds/ru11 !
sub digit_error {
$AGI->exec('Wait',"1");
$AGI->exec('Playback',"ru11/an-error-has-occured");
$AGI->exec('Playback',"ru11/check-number-dial-again");
exit 0;
}
# звуковые файлы в директории digits мною были заменены с
# английского на русский аналог, все с того же сайта. На самом
# деле это не совсем верно, по идее Астериск должен цеплять
# русские файлы после переопределения глобальной переменной LANG,
# однако сходу у меня не получилось, потому исправил ситуацию
# простым копированием файлов.
# Данная функция, корректно для нашего чисто русского слуха, озвучивает день!
sub say_day {
$sayday=$_[0];
if ("$sayday" < 20) {
$AGI->exec('Playback',"digits/h-$sayday\\n");
} elsif ( 20 < "$sayday" and "$sayday" < 30 ) {
$sayday=~/\d(\d)/;
$AGI->exec('Playback',"digits/20");
$AGI->exec('Playback',"digits/h-$1\\n");
} elsif ( "$sayday" == 20 ) {
$AGI->exec('Playback',"digits/h-20n");
} elsif ( "$sayday" == 30 ) {
$AGI->exec('Playback',"digits/h-30n");
} else {
$AGI->exec('Playback',"digits/30");
$AGI->exec('Playback',"digits/h-1\\n");
}
}
# берем локальное время и разбиваем на переменные
($sec2,$min2,$hour2,$mday2,$mon2,$year2,$wday2,$yday2,$isdst2)=localtime($datesec);
# не забываем к году прибавить 1900 а к месяцу единичку
$tmpyear2=$year2+1900;
$tmpmon2=$mon2+1;
# для проверки работы скрипта выводим на экран информацию, когда у нас задание стартовало.
$AGI->exec('NoOp',"Старт_задания_$tmpyear2.$tmpmon2.$mday2\_в_$hour2:$min2");
#####
# если пользователь ввел в поле дата 8 цифр, значит он имел ввиду четкую дату!
if (length($wdate) eq "8") {
$wdate =~ /(\d{4})(\d{2})(\d{2})/;
$timestamp1 = timelocal($sec2,$min2,$hour2,$3,$2-1,$1-1900);
# если ввел 0 - значит имел ввиду что запустить будильник сегодня
} elsif ($wdate eq "0") {
$timestamp1=$datesec;
# если ввел 2-х значное число, значит имел ввиду что пускть задание через сколько то дней.
} elsif (length($wdate) ge "1" and length($wdate) le "2" and $wdate ne "0") {
$timestamp1=$datesec + $wdate*86400;
# ну а если ерунду ввел, значит говорим ему об этом в мягкой форме и отключаемся
} else {
&digit_error;
}
# обратите внимание, я не делал проверку на правильность ввода
# даты, т.е. система проверяет, кол-во дней в месяце, месяцев в
# году, что не есть хорошо, но на мой взгляд это не критично!
####
# Та же операция с временем
if (length($wtime) eq "4") {
$wtime =~ /(\d{2})(\d{2})/;
$timestamp=$timestamp1-(localtime($datesec))[2]*3600-(localtime($datesec))[1]*60+($1*3600)+($2*60);
} elsif ($wtime eq "0") {
$timestamp=$timestamp1+60;
} elsif (length($wtime) ge "1" and length($wtime) le "3") {
$timestamp=$timestamp1+$wtime*60;
} else {
$AGI->exec('NoOp',"Не_верно_задано_время");
&digit_error;
}
####
($sec1,$min1,$hour1,$mday1,$mon1,$year1,$wday1,$yday1,$isdst1)=localtime($timestamp);
$mon_sound="mon-$mon1";
$mon1++;
$year1=1900+$year1;
# В результате хитрых и не очень операций, получаем время, когда
# необходимо позвонить нашему абоненту!
$AGI->exec('NoOp',"Выполнение_задачи_$year1.$mon1.$mday1\_в_$hour1:$min1");
####
# если же дата выполнения задачи ранее текущей даты, значит
# пользователь ошибся при вводе даты и времени
if ($timestamp le $datesec) {
$AGI->exec('NoOp',"Дата_задания_меньше_текущего_времени!");
&digit_error;
}
####
# проделываем похожую операцию с номером куда будем звонить, при 0
# - звоним сами себе, если длина введенных цыфр от 3-х до 4-х,
# значит это локальный звонок, если ни то не другое, пользователь
# имел ввиду что звоним на внешний номер!
if ( $wnum eq "0" ) {
$ch="SIP/$src";
$dst="$src";
} elsif ( length($wnum) eq "4" or length($wnum) eq "3") {
$ch="SIP/$wnum";
$dst="$wnum";
} else {
$ch="SIP/$wnum\@$trunk";
$dst="$wnum";
}
#формируем имя файла для звонка
$records="$year1$mon1$mday1\-$hour1$min1-$dst";
$filename="/var/lib/asterisk/sounds/records/$records.sln";
CICLE3:
# Приятный женский голос говорит - оставьте сообщение после
# сигнала, затем нажмите решетку или повесьте трубку. Вешать
# трубку не следует, т.к. нам необходимо будет подтвердить запись,
# потому необходимо после надиктованного сообщения нажать решетку
$AGI->exec('Playback',"ru11/vm-intro");
$AGI->exec('Record',"records/$records.sln||10");
CICLE2:
# Тут мы озвучиваем само сообщение и куда и когда оно будет отправлено
$AGI->exec('Playback',"ru11/vm-soobshenie");
$AGI->exec('Playback',"ru11/na-nomer");
$AGI->exec('SayDigits',"$dst");
$AGI->exec('Playback',"digits/at");
$AGI->exec('Playback',"digits/day-$wday1");
&say_day($mday1);
$AGI->exec('Playback',"digits/$mon_sound");
$AGI->exec('Playback',"digits/at");
$AGI->exec('SayNumber',"$hour1");
$AGI->exec('Playback',"ru11/hours");
$AGI->exec('SayNumber',"$min1");
$AGI->exec('Playback',"ru11/minutes");
$AGI->exec('Playback',"records/$records");
# ввели счетчик возварата к прослушки или записи, что бы пользователь не заигрывался.
$count++;
if ($count eq "5") { $AGI->exec('Playback',"ru11/goodbye");
unlink($filename); exit 0; }
# подтверждаем запись (нажмите 1-н что бы принять сообщение 2-а
# что бы прослушать, 3-и что бы записать его заново)
$AGI->exec('Read',"rep|ru11/vm-review|1||1|5");
$rep = $AGI->get_variable("rep");
if ( $rep eq "2" ){
goto CICLE2;
} elsif ( $rep eq "3" ) {
unlink($filename);
goto CICLE3;
# если пользователь вводит 1-н, тем самым подтверждая запись,
# ему говорить что сообщение записано и формируется call файл в
# контексте wakeup экстеншен go, максимальное количество
# попыток дозвона 3, время ожидания на проводе 60 сек. Так же
# говорим что CallID у нас подменяется на NOTE (напоминание),
# это нужно для локальных телефонов с дисплеем, что бы можно
# было понять от кого звонок и передаем переменную в астериск
# date, говорящую когда была сделана запись, а так же
# переменную с именем файла, который будем слушать.
} elsif ( $rep eq "1" ) {
$AGI->exec('Playback',"ru11/vm-msgsaved");
open (CALL, "> /tmp/$records");
print CALL "Channel:$ch\nContext:wakeup\nExtension:go
\nPriority:1\nMaxRetries:3\nRetryTime:60\nWaitTime:60
\nCallerID:NOTE<$src>\nSet:date=$datesec\nSet:src=$src
\nSet:records=$records\n";
close (CALL);
# меняем атрибуты файла, что бы астериск при чтении директории
# outgoing не запускал сразу после перемещения нашего call файла процесс дозвона.
utime($timestamp,$timestamp,"/tmp/$records");
move("/tmp/$records","/var/spool/asterisk/outgoing/$records");
$AGI->exec('Playback',"ru11/goodbye");
exit 0;
}
# попрощались и удалили временный файл.
$AGI->exec('Playback',"ru11/demo-moreinfo");
unlink($filename);
exit 0;
Скрипт рабочий, у Вас могут возникнуть сложности только с модулями, в таком
случае идем на http://search.cpan.org/ и качаем необходимые модули.
Обратите внимание все записанные файлы хранятся в директории
/var/lib/asterisk/sounds/records в формате sln - при создании директории
поменяйте правильно права, иначе работать не будет!
Сообщение записали, теперь нужно бы его прослушать.
Итак скрипт ./reminder_listen.agi
#!/usr/bin/perl
use Asterisk::AGI;
use POSIX;
use File::Copy;
use Time::Local;
$AGI = new Asterisk::AGI;
my %input = $AGI->ReadParse();
$count=0;
sub say_day {
$sayday=$_[0];
if ("$sayday" < 20) {
$AGI->exec('Playback',"digits/h-$sayday\\n");
} elsif ( 20 < "$sayday" and "$sayday" < 30 ) {
$sayday=~/\d(\d)/;
$AGI->exec('Playback',"digits/20");
$AGI->exec('Playback',"digits/h-$1\\n");
} elsif ( "$sayday" == 20 ) {
$AGI->exec('Playback',"digits/h-20n");
} elsif ( "$sayday" == 30 ) {
$AGI->exec('Playback',"digits/h-30n");
} else {
$AGI->exec('Playback',"digits/30");
$AGI->exec('Playback',"digits/h-1\\n");
}
}
# Получаем от Asterisk данные о том, откуда поступило напоминание,
# имя звукового файла и дата когда была сделана запись.
$src = $AGI->get_variable('src');
$records = $AGI->get_variable('records');
$filename="/var/lib/asterisk/sounds/records/$records";
$date = $AGI->get_variable('date');
($sec1,$min1,$hour1,$mday1,$mon1,$year1,$wday1,$yday1,$isdst1)=localtime($date);
$mon_sound="mon-$mon1";
CICLE1:
# Начинаем грузить нашего абонента информацией откуда был сделан
# звонок, когда и что собственно от него хотели!
$AGI->exec('Playback',"ru11/vm-from-phonenumber");
$AGI->exec('SayDigits',"$src");
$AGI->exec('Playback',"digits/at");
$AGI->exec('Playback',"digits/day-$wday1");
&say_day($mday1);
$AGI->exec('Playback',"digits/$mon_sound");
$AGI->exec('Playback',"digits/at");
$AGI->exec('SayNumber',"$hour1");
$AGI->exec('Playback',"ru11/hours");
$AGI->exec('SayNumber',"$min1");
$AGI->exec('Playback',"ru11/minutes");
$AGI->exec('Playback',"records/$records");
# В конце концов ошарашенного таким напором абонента мы
# переспрашиваем, хочет ли он еще раз прослушать наше сообщение,
# если да то у него еще в запасе 4-ре раза прослушки, далее цикл
# прервется и система ему скажет goodbye, удалит файл и повесит трубку.
$AGI->exec('Read',"rep|ru11/vm-repeat|1||1|5");
$rep = $AGI->get_variable("rep");
if ( $rep eq "5" ){
$count++;
$AGI->exec('NoOp',"$count");
if ($count eq "3") {
$AGI->exec('Playback',"ru11/goodbye");
unlink($filename); exit 0;
}
goto CICLE1;
}
unlink($filename);
exit 0;
Вот собственно и все. Как мог подробно изложил информацию. Конечно во многих
местах код можно более изящно написать, но данная система работает довольно стабильно.
|
|
|
|
|
Использование Voice-VLAN на Cisco Catalyst для IP-телефона Nortel (доп. ссылка 1) |
Автор: Gleb Poljakov
[комментарии]
|
| Как удалось выяснить и опробовать на практике, Cisco Catalyst может передавать
информацию о Voice-VLAN на IP-телефоны Nortel.
Для этого на коммутаторе достаточно включить протокол LLDP и прописать
voice-vlan на порту телефона:
#conf t
#lldp run
#int fa1/0/1
#switchport voice-vlan 10
И конечно нужно чтобы на телефоне тоже был включен LLDP, указано тэгировать
Voice-VLAN и конфигурировать его автоматически. Также на телефоне необходимо
отключить тэгирование в Data-VLAN.
Тестирование проводилось на коммутаторе Catalyst 3750-24TS (IOS 12.2(46)) и
телефонах Nortel 1110 и 1120.
Ссылки:
* Michael McNamara - LLDP with Cisco 3750 (http://blog.michaelfmcnamara.com/2009/01/lldp-with-cisco-3750/)
* LLDP-MED and Cisco Discovery Protocol (http://www.cisco.com/en/US/technologies/tk652/tk701/technologies_white_paper0900aecd804cd46d.html)
Configuring LLDP and LLDP-MED (http://http//www.cisco.com/en/US/docs/switches/lan/catalyst3750/software/release/12.2_46_se/configuration/guide/swlldp.html)
|
|
|
|
|
Архивирование VoIP разговоров |
Автор: Pavel Pogodin
[комментарии]
|
| Установка oreka ( http://sourceforge.net/projects/oreka/ ) записи разговоров на Debian lenny.
Oreka представляет собой систему для записи аудио потоков VoIP SIP, Cisco Skinny (SCCP),
raw RTP или принимаемых через звуковую карту. Есть web-интерфейс для поиска и
прослушивания записей из базы.
apt-get install subversion
apt-get install sox g++ libtool libxml2-dev liblog4cxx9-dev libace-dev \
libboost-dev libpcap0.8-dev libxerces-c2-dev libsndfile1-dev automake
svn co https://oreka.svn.sourceforge.net/svnroot/oreka/trunk oreka
cd oreka/orkbasecxx/
cat /usr/share/aclocal/libtool.m4 >>aclocal.m4
automake -a
libtoolize --force
make -f Makefile.cvs
На ошибки не обращаем внимание и повторяем последние две команды.
automake -a
make -f Makefile.cvs
Ну вот, теперь можно собирать
./configure
make
make install
cd ../orkaudio/
cat /usr/share/aclocal/libtool.m4 >>aclocal.m4
libtoolize --force
automake -a
make -f Makefile.cvs
Повторяем последние две команды
automake -a
make -f Makefile.cvs
./configure
make
make install
orkaudio debug
|
|
|
|
|
SIP Линк между Cisco 2811 и Asterisk |
Автор: urpyLLIKa
[комментарии]
|
| На Cisco делаем следующее
voice service voip
allow-connections h323 to h323
allow-connections h323 to sip
allow-connections sip to h323
allow-connections sip to sip
redirect ip2ip
sip
registrar server expires max 3600 min 3600
redirect contact order best-match
no call service stop
Делаем преобразование номера (убираем префикс 70)
translation-rule 70
Rule 0 700 0
Rule 1 701 1
Rule 2 702 2
Rule 3 703 3
Rule 4 704 4
Rule 5 705 5
Rule 6 706 6
Rule 7 707 7
Rule 8 708 8
Rule 9 709 9
Описываем куда будем отсылать звонки если наберем префикс 70
dial-peer voice 116 voip
corlist outgoing call-longdistance
destination-pattern 70...
progress_ind setup enable 3
translate-outgoing called 70
session protocol sipv2
session target ipv4:XXX.XXX.XXX.XXX:5060
session transport udp
dtmf-relay rtp-nte
codec g711ulaw
fax rate 9600
fax protocol pass-through g711alaw
clid substitute name
no vad
где XXX.XXX.XXX.XXX - Asterisk
sip-ua
authentication username <USER> password <password>
nat symmetric check-media-src
retry invite 3
retry response 3
retry bye 3
retry cancel 3
retry options 0
timers trying 1000
sip-server ipv4:xxx.xxx.xxx.xxx
где xxx.xxx.xxx.xxx - Asterisk, <USER> - авторизация на Asterisk-е, <password>
- пароль на Asterisk-е
На Asterisk
<users.conf>
[DO2]
allow = ulaw
context = DID_DO2
dialformat = ${EXTEN:1}
hasexten = yes
hasiax = no
hassip = yes
host = yyy.yyy.yyy.yyy
port = 5060
registeriax = no
registersip = yes
secret = <pass>
trunkname = Custom - DO2
trunkstyle = customvoip
username = <user>
disallow = alaw,gsm,ilbc,g726,adpcm,speex,lpc10,g729
md5secret = <md5_pass>
insecure = port,invite
canreinvite = no
yyy.yyy.yyy.yyy - Cisco
<user> - пользователь
<pass> - пароль
<md5_pass> - пароль в MD5
<extensions.conf>
DO2 = SIP/DO2
[numberplan-custom-1]
plancomment = DialPlan1
include = default
comment = _2XXXX!,1,default,standard
include = default
exten = _02XXX,1,Macro(trunkdial,${DO2}/${EXTEN:2})
comment = _02XXX,1,DO2,standard
[DID_DO2]
include = default
include = default
include = default
[numberplan-custom-2]
include = default
plancomment = DialPlan2
exten = _2XXX!,1,Macro(trunkdial,${trunk_1}/${EXTEN:0})
comment = _2XXX!,1,d1,standard
рестартуем Астериск.
При наборе префикса 02 с Астериска будет производиться проброс на Cisco.
При наборе 70xxx со стороны Cisco проброс будет производиться на Asterisk.
Для упрощения конфигурирования, можно воспользоваться утилитой asterisk-gui
(/usr/ports/www/asterisk-gui для BSD like ports)
|
|
|
|
|
Пропуск звонка без идентификатора номера вызывающего абонента в пакете АОН через CISCO 5350 |
Автор: Вячеслав Калинин
[обсудить]
|
| Эта заметка, возможно, окажется полезной начинающим. Настраивая шлюз 5350,
столкнулся со следующей проблемой - звонок отлично проходил во все стороны,
но если при звонках с ТФОП в пакете АОН отсутствовал идентификатор абонента А,
звонок заворачивался на модемный пул CISCO 5350.
Такая ситуация встречалась например, при звонках с сотового телефона у которого
включена услуга анти-АОН,
а так же при звонках с некоторых АТС, в частности из Горно-Алтайска.
Решение вопроса оказалось очень простым - для пропуска таких звонков,
необходимо во входящем диал-пире установить answer-address T:
dial-peer voice 20 pots
description #Incoming from POTS
huntstop
answer-address T
incoming called-number .T
direct-inward-dial
port 3/0:D
forward-digits all
В случае отсутствия answer-address T, звонок без АОН проключается на модемный пул.
Регулярное выражение Т подразумевает любое количество цифр, включая 0,
что соответствует и случаю отсутствия идентификатора вызывающей стороны.
|
|
|
|
|
VoIP, односторонняя слышимость на шлюзах cisco (доп. ссылка 1) |
Автор: Anton V. Yuzhaninov
[комментарии]
|
| Иногда проблемы с односторонней слышимостью возникают из за того, что выключен роутинг,
поэтому его стоит включать на VoIP-шлюзах cisco:
ip routing
Если это не помогло, то что смотреть дальше написано в документе
Troubleshooting One Way Voice Issues (http://www.cisco.com/en/US/tech/tk652/tk698/technologies_tech_note09186a008009484b.shtml)
|
|
|
|
|