Согласование медиакодеков в FreeSwitch

Опубликовано в Freeswitch

Согласование медиакодеков в FreeSwitch, транскодинг

FreeSWITCH поддерживает два основных режима согласования кодеков: early (ранний) или late (поздний). Раннее согласование означает, что кодек будет согласован между FreeSWITCH и конечной точкой как можно раньше, даже до того, как FreeSWITCH потребуется отправить медиа (например, звонок) или ответить на вызов. Это происходит до того, как входящий вызов попадает в диалплан. Позднее согласование означает отложить выбор кодека до тех пор, пока вызов не достигнет диалплана, и не будет собрана дополнительная информация. Эта дополнительная информация может использоваться для влияния на процесс согласования. Давайте проиллюстрируем различия между ранним (early) и поздним (late) согласованием.

 Рассмотрим следующую настройку:

  • у Алисы есть телефон с кодеками G722 и PCMU
  •  у Боба есть телефон с PCMU и PCMA
  •  FreeSWITCH имеет список исходящих кодеков “codec prefs” G722, G722.1, PCMU, PCMA, G729

(Это список кодеков, которые FS предложит для всех исходящих вызовов).

Раннее согласование:

Алиса (A) набирает Бобу (B);
Вызов поступает FS и предлагает два кодека: G722 и PCMU;
FS видит эти два кодека и сразу выбирает G722 для ноги A;
FS вызывает B и предлагает G722, G722.1, PCMU, PCMA, G729;
B видит этот список кодеков и выбирает PCMU;
FS делает бридж от A до B;
FS транскодирует G722 в PCMU;

Позднее согласование с установкой "inherit codec":

Алиса (A) набирает Бобу (B);
Вызов поступает FS и предлагает два кодека: G722 и PCMU;
FS видит эти два кодека, но делает * NOT * выбирает только эти кодеки;
FS обращается к B и предлагает G722 и PCMU;
B видит эти два кодека и выбирает PCMU;
FS теперь выбирает PCMU на ноге A;
FS делает бридж от A до B;
A и B связаны с PCMU для PCMU (без дополнительной перекодирования);

Обратите внимание на разницу во времени согласования кодека A-ноги. С началом согласования FreeSWITCH сразу выбирает кодек (G722). Он не ждет, чтобы узнать, что происходит на исходящем участке (то есть B-ноге) вызова. Таким образом, A-нога использует G722. После определения кодека для A-нога FreeSWITCH передает этот вызов через диалплан, который, в конечном счете, приходит в приложение-бридж для вызова телефона Боба. Чтобы инициировать бридж, FreeSWITCH вызывает B-ногу и предлагает довольно большой список кодеков. Это “outbound codec prefs” для FreeSWITCH. (Этот список настраивается, но об этом позже.) Телефон Боба видит все эти кодеки и выбирает первый, который соответствует, в данном случае PCMU. На данный момент у нас есть две согласованные ноги:

  • A-нога использует G722;
  • B-нога использует PCMU;

Как только телефон Боба отправляет сигнал вызова, обе ноги соединяются вместе. FreeSWITCH должен транскодировать кодек Алисы (G722) в кодека Боба (PCMU), потому что были согласованы два разных кодека. Обычно это нормально, но предположим, что вы предпочли бы, чтобы на обоих телефонах был один и тот же кодек, чтобы было меньше использования CPU вашего сервера. Это то, где поздние согласования вступают в игру.

Как вы можете видеть, когда FreeSWITCH выбирает кодек для A-ноги, не зная, какой кодек установлен в B-ноге, тогда легко может возникнуть несоответствие кодека (codec mismatch). “Несоответствие” кодека не всегда плохо, но намного приятнее, когда обе ноги вызова используют один и тот же кодек. Используя поздние согласования и технику под названием “inherit codec”, мы можем заставить A-ногу использовать тот кодек, который ранее предлагался B-ноге. (Этот процесс описывается более подробно позже - сейчас мы рассматриваем только базовые концепции).

Во втором примере, вызов принятый FreeSWITCH, через A-ногу делает *not* сразу же согласовывая кодек. Вместо этого FreeSWITCH останавливает согласование кодека для A-ноги до тех пор, пока A-нога не пройдет через диалплан. В этом случае диалплан сталкивается с бриджем на телефоне Боба. Во время процесса установления бриджа FreeSWITCH обсудил кодек с телефоном Боба - в этом случае PCMU. Как только этот кодек был выбран на B-ноге, FreeSWITCH вернулся к телефону Алисы и сказал, что мы будем использовать PCMU на A-ноге. Теперь обе ноги вызова используют один и тот же кодек, что нам и требовалось.

В этом действительно и есть вся разница между ранним и поздним согласованием. Просто имейте это в виду: только включение позднего согласования автоматически не заставляет A-ногу наследовать кодек B-ноги. Это просто позволяет “inherit codec” (наследовать кодек) как один из способов согласования кодеков. Позднее согласование разрешает другие трюки для согласования кодеков. 

Ранние согласование “Early Negotiation” (поведение по умолчанию)

Когда на этапе A вызывается FreeSWITCH, предлагаемые кодеки будут сравниваться с содержимым “inbound-codec-prefs” в соответствующем профиле SIP. Как только кодек, предложенный A, сравнивает кодек разрешенный FS, он выбирается как кодек для A-ноги. Если ни один из предложенных кодеков не соответствует разрешенным кодекам, вызов терпит неудачу.

Примечание: Из-за этого алгоритма, порядок кодеков во входящем SDP имеет приоритет в коде кодеков в “inbound-codec-prefs”.

Когда FS вызывает B-ногу, список кодеков в “outbound-codec-prefs” для профиля SIP реорганизуется путем выбора кодека, согласованного выше для A-ноги вверху. Если B не принимает какой-либо из кодеков, очевидно, что вызовы терпят неудачу.

Так, например:

A -------- GSM/PCMA/G729 --------> FS (allowing G729/PCMA/PCMU) -------- PCMA/G729/PCMU --------> B
  • A предлагает GSM / PCMA / G729 для FS.
  • FS проверяет предложенные кодеки в порядке приоритета (как указано в SDP) в отношении списка разрешенных кодеков (как это описано в inbound-codec-prefs) и выбирает PCMA в качестве первого авторизованного кодека, поэтому список кодеков становится следующим: PCMA / G729 / PCMU.
  • FS предлагает этот список кодеков B.

Параметры раннего согласования:

disable-transcoding

Это параметр, который вы можете установить в исходящем SIP профиле. Это вынудит кодек, предложенный для ноги B (исходящая нога), быть тем же, что и кодек, согласованный на этапе A (входящая нога).

<param name="disable-transcoding" value="true"/>

Примечание: обычно неправильно понимается, что этот параметр отключает возможность транскодирования в FS. Это не правильно.

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

Тот же результат может быть достигнут установкой absolute_codec_string в значение входящего кодека.

Этот параметр (применяется только в случае, когда позднее согласование выключено) принимает согласованный кодек из А-ноги и предлагает его как единственный вариант в B-ноге (игнорируя любые другие настройки кодека), если B-нога не может использовать тот же кодек, вызов будет неудачным.

absolute_codec_string

Это переменная канала, которую вы можете установить в диалплане, как правило, перед бриджем. Это заставит список кодеков, предложенных к B-ноге, не принимать во внимание что-либо еще.

Вот пример:

<action application="export" data="nolocal:absolute_codec_string=PCMA,PCMU"/>
<action application="bridge" data="sofia/gateway/mygateway/mynumber"/>

Или

<action application="bridge" data="{absolute_codec_string='PCMA,PCMU'}sofia/gateway/mygateway/mynumber"/>

Убедитесь, что у вас есть одинарные кавычки ('PCMA, PCMU'), разделенные запятыми (',') кодеки, чтобы защитить их от анализа списка переменных внутри {var1 = val1, var2 = val2, absolute_codec_string = 'GSM, PCMU' }

Примечание: Этот параметр преобладает при disable-transcoding. Поэтому, если вы отключите транскодирование в исходящем профиле SIP и используете absolute_codec_string в диалплане, чтобы установить то, что исходящий кодек отличается от входящего кодека, транскодирование будет происходить в любом случае.

codec_string

Это переменная канала, которую вы можете установить в диалплане, как правило, перед бриджем. Определенный список кодеков переопределит тот, который установлен в параметре outbound-codec-prefs в исходящем профиле.

Вот пример:

<action application="export" data="nolocal:codec_string=PCMA,PCMU"/>
<action application="bridge" data="sofia/gateway/mygateway/mynumber"/>

или

<action application="bridge" data="{codec_string='PCMA,PCMU'}sofia/gateway/mygateway/mynumber"/>

Early Negotiation + Disable Transcoding:

<param name="disable-transcoding" value="true"/>

Если этот параметр профиля sofia установлен, все приглашаемые вами B-ноги будут содержать *only* только кодек, согласованный A-ноге. Также в любом случае переменная codec_string на A-ноге управляет тем, какие кодеки будут предложены B-ноге.

Переменная "absolute_codec_string" подобна, за исключением того, что подразумевает неявный список кодеков и отключит добавление кодека A-ноги в список, как описано в поведении по умолчанию.

Позднее согласование (требуется параметр)

<param name="inbound-late-negotiation" value="true"/>
  • вызов пройдется по диалплану, вообще не глядя на кодеки;
  • согласование будет иметь место, когда  A-нога будет выполнена;
  • это позволяет перенаправить звонок на скрипт и проверить sdp, переписать приемлемые кодеки с помощью переменной канала "codec_string";

inherit_codec

<action application="set" data="inherit_codec=true"/>

inherit_codec=true (применимо только при включенном позднем согласовании) будет выбираться согласованный кодек, когда B-нога ответит и передаст его A-ноге, чтобы она также использовала тот же кодек (если A-нога его поддерживает); В противном случае он будет использовать все доступное, из своего собственного списка.

ep_codec_string

Эта переменная доступна только в том случае, если в профиле включено позднее согласование. Читаемая строка, содержащая все кодеки, предложенные вызывающей конечной точкой, это можно легко проанализировать в диалплане.

<action application="export" data="codec_string='${ep_codec_string}'"/>

Микширование медиа/кодеков на разных ногах (транскодирование)

Если вы хотите, чтобы FreeSWITCH мог устанавливать соединение между двумя ногам с разными кодеками (выполняя транскодирование), вам нужно установить несколько переменных, чтобы сделать это возможным. Сначала необходимо установить media_mix_inbound_outbound_codecs=true глобально (т.е. vars.xml) или в B-ногу явно на бридже

<action application="bridge" data="{media_mix_inbound_outbound_codecs=true}sofia/gateway/....">

Эта новая переменная требуется с версией 1.6 и более поздних версий из-за поддержки webrtc и постоянно растущего размера SDP, когда задействован SIP поверх UDP. Теперь SDPs достигли точки, когда становится все труднее и труднее переводить вызовы из WebRTC -> SIP и сохранять исходный SDP, из-за сдвига размера SDP. При использовании SIP поверх UDP, когда происходит фрагментация пакетов, он уничтожает пакет SIP, поскольку UDP не автособирает фрагменты ... это происходит, когда ваши пакеты SIP превышают MTU ... единственное исправление - небольшие пакеты. Это означает компактные заголовки, устраняя лишние заголовки или просто не применяя такой большой SDP, устраняя кодеки, которые вам не нужны. Аффект с FS, если у вас нет media_mix_inbound_outbound_codecs в true, то только кодеки, предлагаемые FS на A-ноге передаются в B-ногу, это уменьшает размер SDP и имеет побочный эффект, значительно уменьшая количество транскодирования.

Во-вторых, вы захотите отключить inbound-late-negotiation и inbound-zrtp-passthru (второй заставляет первое значение в true), или вы захотите предварительно ответить на A-ногу до бриджа.

Наконец, вы должны убедиться, что у вас есть такие переменные, как disable-transcoding, inherit_codec, bypass_media, proxy_media, все установлены в false (поскольку все они тангенциальны тому, что мы хотим достичь).

<param name="disable-transcoding" value="false"/>
<param name="inherit_codec" value="false"/>
<param name="bypass_media" value="false"/>
<param name="proxy_media" value="false"/>

Коментарии: