Архив рубрики: Freeswitch: Dialplan

Freeswitch: Dialplan. Conditions

http://pro-voip.com.ua freeswitch

Multiple Conditions (Logical AND)

Действие выполняется, когда все условия выполняются.

<condition field="destination_number" expression="^500$"/>
<condition wday="1">
    action(s)...
</condition>

— здесь action выполняется только если destination_number=500 и день недели — воскресенье. Если хоть одно из условий вернет false, Freeswitch перейдет к anti-action, а если anti-action не задан, то к следующему extension.

 

Nested Conditions — вложенные условия

require-nested  важный атрибут в nested conditions. Этот атрибут определяет, должно ли вложенное условие (sub-condition) вернуть значение true, чтобы выполнился action в родительском условии (top-level condition). Принимает значения: true или false;
Default: require-nested=true.

Если require-nested=true — sub-condition тоже должно вернуть true или иметь параметр break=never, чтобы выполнился action в родительском condition. При этом выполняются action, определенные и в sub-condition, и в top-level condition — и именно в таком порядке — сначала выполняются все action во всех sub-condition, а только потом все action в top-level condition (порядок записи не играет роли — даже если сначала записан action, а потом описан sub-condition).

! Обрабатываются сначала вложенные condition

Если require-nested=false — то неважно, что вернет sub-condition, action в родительком condition в любом случае выполнится.

 

break — флаг condition —  при каком результате проверки условия остановить обработку данного extension и перейти к следующему extension. Принимает значения: on-false, on-true, never;
Default: break=on-false;

break можно указывать в цепочке из условий, например, при создании логики Logical AND.

break применяется и в nested conditions (sub-condition). В обычной работе без указания данного флага (при require-nested=true и break=on-false — это дефолтные значения), если первый sub-condition возвращает false, то следующий (sub)-condition (если он есть) уже не проверяется, и в целом работа с данным extension прекращается и парсится уже следующий extension.

Так вот, если указать в первом sub-condition break=never, то даже если он вернет false, следующий за ним sub-condition проверяться будет!

 

Пример:

в top-level condition указан require-nested=false — результат проверки вложенных условий не повлияет на выполнение action в родительском condition); в sub-condition’ах указан флаг break=never — не прерывать выполнение всего extension, разрешить проверку следующих condition.

<extension name="nested_example">
  <condition field="destination_number" expression="^1234$" require-nested="false">
    <action application="log" data="INFO I'm before the nested conditions..."/>

    <condition field="${foo1}" expression="bar1" break="never">
      <action application="log" data="INFO foo1 is bar1" />
    </condition>

    <action application="log" data="INFO I'm in between the nested conditions..."/>

    <condition field="${foo2}" expression="bar2" break="never">
      <action application="log" data="INFO foo2 is bar2" />
    </condition>

    <action application="log" data="INFO I'm after the nested conditions..."/>

  </condition
</extension>

Для чего break=never для второго sub-condition? Ведь после него больше sub-condition нет. Да, но после второго sub-condition еще есть top-level condition, ведь проверка условий будет выполняться в следующем порядке: sub-condition 1, sub-condition 2, top-level condition — сначала по порядку все вложенные, и только потом родитель.

В итоге после выполнения данного extension у нас в логах будут записи в такой очередности:

<action application="log" data="INFO foo1 is bar1" />
<action application="log" data="INFO foo2 is bar2" />
<action application="log" data="INFO I'm before the nested conditions..."/>
<action application="log" data="INFO I'm in between the nested conditions..."/>
<action application="log" data="INFO I'm after the nested conditions..."/>

 

Multiple Conditions (Logical OR, XOR)

Логическое ИЛИ — action выполняется, если хоть одно из условий возвращет true.

Если ИЛИ нужно организовать для одного поля, т.е. смотрим только на одну переменную, то можно воспользоваться следующей конструкцией:

<condition field="destination_number" expression="^501|502$">
    action(s)...
</condition>

— action будет выполнен, если destination_number 501 ИЛИ 502.

Если ИЛИ для разных полей, используется regex.

<condition regex="all|any|xor">
  <regex field="some_field" expression="Some Value"/>
  <regex field="another_field" expression="^Another\s*Value$"/>
  <action(s) ...>
  <anti-action(s)...>
</condition>

regex может иметь следующие значения:

  • all — logical AND — все условия должны вернуть true, чтобы выполнилось action;
  • any — logical OR — хотя бы одно из условий должны возвратить true, чтобы выполнилось action;
  • xor — logical XOR — только одно условие должно возвратить true, чтобы выполнилось action;

 

Комплексный пример — маршрутизация по времени (time-based routing):

Пользователь звонит на extension 1100. Вызов перенаправляется на extension 1105 с понедельника по четверг с 8:00 до 21:59. В пятницу звонок перенаправляется на 1105 с 8:00 до 12:59. Во все остальное время вызовы перенаправляются в голосовую почту.

<extension name="Time-of-day-tod">
    <!--если это условие false, FreeSWITCH переходит к следующему *extension*.-->
    <condition field="destination_number" expression="^1100$" break="on-false"/>

    <!-- Если это условие возвращает true, следующее уже не проверяем-->
    <condition wday="6" hour="8-12" break="on-true">    <!--пятница с 8 до 12:59 -->
        <action application="transfer" data="1105 XML default"/>
    </condition>

    <condition wday="2-5" hour="8-21" break="on-true">   <!--понедельник-четверг с 8 до 21:59-->
        <action application="transfer" data="1105 XML default"/>
    </condition>

    <condition> <!-- перенаправление в голосовую почту в остальное время -->
        <action application="voicemail" data="default ${domain} 1105"/>
    </condition>
</extension>

— в первом condition в данном примере можно было и не указывать break=on-false, ведь это значение по умолчанию, если не задано другое.

Больше примеров в wiki.freeswitch.org

Freeswitch: Dialplan

http://pro-voip.com.ua freeswitch Для начала, что такое диалплан. Диалплан — это схема маршрутизации вызовов (звонков). В диалплане мы проверяем некоторые параметры вызова (например, номер вызывающего и вызываемого абонента) и на основании значения этих параметров указываем, куда перенаправить этот вызов дальше — на локальный номер, на шлюз оператора, в голосовую почту и т.д.

Для Freeswitch дефолтным диалпланом является XML dialplan. XML dialplan подключается к главному конфигурационному файлу freeswitch.xml с помощью include:

Диалплан может быть поделен на контексты (context) для разделения правил обработки и маршрутизации между разными группами пользователей. Пользователь с одним контекстом не может воспользоваться диалпланом другого контекста. Но существует возможность перенаправления вызовов между контекстами с помощью приложений диалплана (application).

Когда поступает входящий вызов, он поступает не из-неоткуда, он поступает от какого-либо зарегистрированного на Freeswitch абонента (будь то локальный абонент, или gateway оператора, или вызов может быть сгенерирован самим Freeswitch) и попадает сперва в обработку модуля mod_sofia. В Sofia вычисляются значения канальных переменных — channel variables — на основании значений в sip-заголовках входящего вызова, согласованных параметров вызова между вызывающим абонентом и Freeswitch, параметров, выставленных вручную в directory. Затем уже Freeswitch, используя вычисленные канальные переменные, парсит диалплан в поисках подходящего направления для данного вызова.

Диалплан работает по принципу «условие-действие»; «условие» задается в виде регулярного выражения — используется синтаксис Perl Regular Expression; «действие» — это одно или несколько приложений Freeswitch, также в качестве «действия» можно подключать свои внешние скрипты.

XML dialplan состоит из таких структурных единиц, как:

  • context (контекст),
  • extension («направление»),
  • condition (условие),
  • action (действие).

context состоит из множества extension, которые с помощью condition определяют action.

 

context

— логическое разделения групп правил маршрутизации вызовов.

Когда вы создаете пользователя в directory,  в переменной «user_context» вы указываете контекст, который пользователь может использовать для совершения вызовов — тем самым вы определяете набор доступных extension (направлений) для данного пользователя или группы пользователей, или всего домена. Если вы этого не сделаете, будет применяться контекст, указанный в переменной «context» sip-профиля.

Из выше сказанного и знаний про работу sip-профиля можно сделать следующие выводы: в sip-профиле может быть сколько угодно контекстов; в домене может быть сколько угодно контекстов; можно отдельного пользователя в домене завернуть в его отдельный контекст и чисто для этого пользователя написать диалплан; можно один контекст использовать для нескольких доменов.

context имеет обязательный параметр — это «name» — он должен быть уникальным. Для значения параметра name есть зарезервированное слово any — которое означает «любой контекст».

extension

— это отдельное направления для вызова — упрощенно — отдельная пара «условие-действие».

Также имеет обязательный параметр «name«, значение этого параметра может быть неуникальным; используется для описания extension — часто в name кратко описывают, что делает данный extension — это облегчает восприятие диалплана при просмотре его «глазками» без необходимости лезть внутрь самого екстеншена. При принятии решения о маршрутизации вызова Freeswitch парсит extension’ы и как только находит подходящий, на нем и останавливается, не досматривая остальные extension’ы до конца.

condition

— условие для выбора.

Здесь задаем, какую переменную проверяем, и под какое условие должно попасть значение этой переменной, чтобы применился данный extension. Можно сохранить значение всей переменной или непрерывную часть значения, для того, чтобы ее дальше можно было использовать в action. Для этого регулярное выражение или часть регулярного выражения заключаем в круглые скобки ( ). То, что окажется в пределах круглых скобок, сохранится в специальных переменных — $1, $2$9. Поскольку condition’ов может быт несколько, то и скобок в регулярных выражениях может быть несколько. Значение, попавшее в первые скобки, заносится в переменную $1, во вторые — $2 и т.д.

На примере:

здесь мы проверяем номер вызываемого абонента (destination_number) — он должен состоять из любых 4-х цифр. Если условие выполняется — то последние 2 цифры заносятся в переменную $1. Например, если destination_number=3589, то переменная $1=89.

Если после переменной $N нужно записать еще какую-то цифру, число, то используем фигурные скобки — ${N}

$1, $2$9 работают только в пределах того extension, где они были вычислены.

Переменных $10, $11, $12 и т.д. здесь не бывает. Если нужно переменных больше, чем 9, есть специальные приемы, но о них как-нибудь потом.

action

действие, которое мы выполняем, если мы попали под условие condition. Здесь мы указываем действие — это может быть направление вызова, установление каких-либо параметров, проигрывание музыки и т.д. Действие — это запуск определенного приложения (application).

В противовес action, есть еще anti-action — это действие, которое выполняется, когда результат проверки условий — false:

 

Написание тегов

Хочу обратить внимание на соблюдение порядка открывающих/закрывающих тегов.

<condition … > — открывающий тег
</condition> — закрывающий тег

<action … /> — не имеет отдельного закрывающего тега, поэтому в конце не забудьте про слеш

Если condition’ов несколько, то все, кроме последнего закрываем с помощью />, а последний condition закрываем  </condition>

<condition  … />
<condition … />
<condition … >
    <action … />
</condition>