четверг, 23 апреля 2015 г.

180, 183, early_media

Early media это информация, которая ходит только в 1 сторону, оно же обычно pre answer. Если медиа нет - телефон сам генерирует гудки, иначе передает то, что прилетает. А это может быть "абонент временно недоступен", просто какая-то информация...

Обычно при установке соединения идут сообщения тип 100 (trying), потом 180 ringing, без медиа, потом 183 session progress, с медиа. Но в рф сотовые и тут выпендрились и медиа у них уже в 180 летит, что несколько ломает поведение фрисвича, хотя по RFC это и допустимо.


Работа с хуками и стартап скриптами

Пример стартап скрипта
con = freeswitch.EventConsumer("CUSTOM","vm::maintenance")
for e in (function() return con:pop(1) end) do
        freeswitch.consoleLog("notice","event\n" .. e:serialize("xml") .. "\n")
        element = nil
        element = e:getHeader("VM-Action")
        if element then
                --
        end
end

Пример хук скрипта
freeswitch.consoleLog("notice","RECORD_STOP\n" .. event:serialize(""))
path = nil
path = event:getHeader("Record-File-Path")
итд.
То есть у нас изначально есть массив event, где лежат все значения ивента. Но при этом недоступны канальные переменные, только глобальные. Можно добавить свои поля в ивент через event:addHeader("API-FileSize", size), и даже сформировать новый ивент (читаем доку), но просто модификация полей не перенесет новые переменные в сессию.

Можно создать привязку к api так:
api = freeswitch.API()
и дальше делать запросы типа
req = urlencode(event:serialize("json"))
data = api:executeString("curl "..  url .. " content-type application/json post " .. req)
Опять же, сессионные переменные будут недоступны, то есть можно сделать eval на строку вида
path =  "$${base_dir}/recordings/archive/${strftime(%Y-%m-%d-%H-%M-%S)}_${caller_id_number}_${destination_number}.wav"
но ${caller_id_number}_${destination_number} будут пустые и на выходе останется только "_". Нужно подобрать подходящие поля в event. Что-то можно заранее в ивент (и сип заголовки) выставить через application=set data="sip_h_X-Caller=12345", появится поле X-Caller.

Есть ещё метод вызова, через lua или luarun, тогда доступны сессионные переменные через массив session, самый простой пример
session:execute("playback", mySound)
в отличии от api:execute, выполняется в контексте текущей сессии, где доступны все переменные.

Также нужно быть предельно аккуратными с freeswitch.EventConsumer -- если такая конструкция появится в хуке на ивент, фрисвич начнёт падать. Точно актуально для 1.4.15, и на момент выхода 1.4.18 никто даже не пытался понять причин. И что самое противное -- падать будет не сразу, а спустя N дней, и при этом КАК БЫ работать. То есть поступает звонок, в логе есть инвайт, есть ответ на него... и всё. ringing уже не будет. Но cancel примет и обработает!

Ну и помним, что стартап скрипты перечитываются ТОЛЬКО при рестарте всего фрисвича целиком! Увы, просто рестартовать модуль lua нельзя. А вот хуки - читаются при каждом обращении к ним, поэтому для повышения скорости их лучше помещать в tmpfs/shm

линки
https://freeswitch.org/confluence/display/FREESWITCH/mod_lua
https://freeswitch.org/confluence/display/FREESWITCH/Lua+API+Reference

среда, 22 апреля 2015 г.

установка таймаутов

Переменные, которые управляют таймаутами:
timeout
leg_timeout
call_timeout (deprecated?)
originate_timeout
progress_timeout

bridge_answer_timeout - таймаут, когда имеется early_media. Имеет баг - в отличии от других таймаутов, через set дропает ногу А с ALLOTTED_TIMEOUT. Ставить или на ногу Б через [], {}, или export

Почти ко всем таймаутам есть предупреждение
WARNING: Beware that if you are not using {ignore_early_media=true} (...) is no longer applicable as soon as early media signal is received.

Ну и несколько специфичных
conference_auto_outcall_timeout
park_timeout
leg_progress_timeout

rtp_hold_timeout_sec
rtp_timeout_sec
SOFIA_SESSION_TIMEOUT

почти вся информация есть тут

про early_media надо сказать отдельно, будет дальше.

генерация тонов

Есть для этого спец модуль tone_stream, общий формат
tone_stream://[L=x;][v=y;]%(<on-duration>, <off-duration>, <freq-1> [, freq-2] [, freq-3] [, freq-n] [;loops=x])

Пример использования
<action application="playback" data="tone_stream://L=100;%(100,100,350,440)" />

Примеры

Непрерывный тон
tone_stream://%(10000,0,350,440)

Звонок формата сша, сам тон в константе
tone_stream://$${us-ring}
оно же
tone_stream://%(2000,4000,440,480)
также интересны ru-ring, uk-ring

опционально ;loops=-1 или {loops=-1}tone...

сложный тон (2 тона)
tone_stream://%(275,10,600);%(275,100,300)

бывает даже так
tone_stream://path=${conf_dir}/tetris.ttml

Более подробное описание и совсем сложные примеры:
https://wiki.freeswitch.org/wiki/TGML

lua json библиотеки

список библиотек
http://lua-users.org/wiki/JsonModules

Также есть pure lua, которая просто копируется в проект
http://regex.info/blog/lua/json
Особенность загрузки - через
JSON = (loadfile "JSON.lua")()
Если будет проблема с загрузкой - тут лучше указать полный путь. Через require не грузится.
Модуль достаточно медленный, но если надо быстро распарсить результат curl - скорости достаточно.

Сравнение производительности
http://www.kyne.com.au/~mark/software/lua-json-performance.html
http://lua-users.org/wiki/JsonModules
наиболее интересным выглядит mp-CJSON / Lua CJSON

понедельник, 20 апреля 2015 г.

lua, execute и curl - получить код ответа

1)
session:execute("curl", some_url)
Код будет в curl_response_code

2)
local response = api:execute("curl", url .. " json timeout 2 get ")
resp = json.decode(response)

if  resp.status_code ~= 200 then ...

среда, 15 апреля 2015 г.

Что за внутренний кодек L16?

В логе можно увидеть такую строку:
[DEBUG] switch_ivr_play_say.c:1314 Codec Activated L16@8000hz 1 channels 20ms

По сути, это чистый WAV, 16 бит на такт, 8кГц, линейное преобразование. Каждые 20 мс сигнала собираются в 1 пакет.
Промежуточный внутренний кодек фрисвича, когда нужно транскодирование, микширование итд.

HD - те же 16 бит, но полоса больше, допустимые значения 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000