Русский
Русский
English
Статистика
Реклама

Телефония

Конференц-связь Snom C520-WiMi и C52-SP Сценарии использования

23.02.2021 12:21:01 | Автор: admin

Здравствуй дорогой читатель!
Как и обещали, мы продолжаем обзор конференц-системы Snom C520-WiMi и спикерфона Snom C52-SP. Поговорим сегодня о предполагаемых сценариях использования этих устройств, как отдельно, так и в связке друг с другом.

Рабочее место дома

Начнем с трендов сезона. За последний год каждый из нас хотя бы раз участвовал в рабочей конференции из дома, а некоторые перешли на постоянный режим работы из уютного домашнего кресла. Естественно при работе из дома вопрос качества звука, в процессе совещания или при разговорах с коллегами и клиентами актуален как никогда. Решать его путем стандартным для офиса далеко не всегда удобно - подключение IP-телефона на удаленном рабочем месте сотрудника задача не стандартная, вероятнее всего придется организовывать VPN-соединение из его домашней сети для безопасного подключения телефона к телефонной станции, да и стоит игра свеч? Кроме того, мы все уже привыкли использовать ноутбук или ПК как одно из основных средств связи дома, так зачем здесь что-то менять? Вам достаточно лишь чуть-чуть усовершенствовать привычную для вас схему. Подключите к вашему домашнему ПК спикерфон C52-SP, используя DECT-донгл A230 и не ограничивайте себя в перемещениях по дому во время переговоров, расположив спикерфон в любом месте, где вам удобно обсуждать рабочие вопросы.

Качество связи на рабочем месте, на удивление просто.

Наверняка, каждый кто хоть раз проектировал и устанавливал систему телефонии в компании, сталкивался с дилеммой оборудования кабинетов крупных начальников. С одной стороны, руководителю необходим современный аппарат, с некоторым количеством BLF-клавиш, с трубкой, с большим дисплеем и удобной клавиатурой. Но помимо этого, телефон должен обладать хорошим качеством громкой связи и не только хорошим качеством звука, но и охватом площади значительно превосходящей стандартное рабочее место. Последнее редко может обеспечить стационарный аппарат, а конференц-телефон слишком узконаправленное устройство для обеспечения всех потребностей, возникающих в работе руководителя. Установка же двух аппаратов задваивает историю вызовов, усложняет настройку и упирается в проблему регистрации нескольких устройств на одном SIP-аккаунте, что до сих пор поддерживается не каждым сервером связи. Казалось бы, это тупик. Но это тупик лишь при попытке подойти к вопросу стандартно, мы же предлагаем чуть иной путь.


На стол руководителю действительно устанавливается стационарный телефон, а спикерфон подключается к нему с помощью DECT-донгла, позволяя использовать все возможности привычного аппарата, а также проводить совещания, используя кабинет руководителя как мини-переговорную.

Оснащение небольших переговорных комнат

Множество раз мы сталкивались в своей работе с тем, что в переговорную комнату практически всегда требуется помимо конференц-телефона установить еще и аппарат для созыва сотрудников на совещание. Использовать для этого конференц-телефон не всегда удобно, поэтому в переговорных обычно размещается DECT-трубка или стационарный аппарат. Но почему бы не использовать данный аппарат как основной источник вызова, обеспечив его качественным акустическим дополнением в виде спикерфона?

Вы получаете стандартный функционал для небольшой переговорной, уменьшение затрат, поскольку спикерфон будет решением более бюджетным чем полноценный конференц-телефон, и мобильность переговорного устройства, так как привязанный по DECT-у спикерфон не связан проводами и легко перемещается в радиусе 50 м от стационарного аппарата.

Переговорные среднего размера.

Для оснащения полноценных переговорных комнат спикерфон как самостоятельное решение уже не подойдет - здесь нужен больший радиус захвата микрофона, собственный номеронабиратель, расположенный прямо на столе переговорной и одновременно появляется необходимость захвата голоса вне основного стола помещения, например если спикеру необходимо изобразить что-либо на доске, как это часто бывает во время совещания.

В этом случае мы предлагаем следующую концепцию: На столе переговорной используется конференц-телефон Snom C520-WiMi. Если вам необходимо отойти от стола для каких-либо действий, вы вынимаете микрофон, являющийся частью устройства в обычное время, и забираете его с собой, обеспечивая хорошую слышимость всем участникам совещания. Беспокоитесь что изменение положения микрофона повлияет на общее качество звука? Не стоит. Микрофоны синхронизированы между собой и обеспечат хорошее качество связи в любом положении.

Конференц-залы и большие переговорные комнаты.

Размышляя об оснащении помещений различных размеров мы с вами добрались и конференц-залов. Принципиальное отличие здесь от предыдущих примеров, во-первых, в гораздо большем размере помещений, а во-вторых в необходимости работы со звуком из нескольких источников, разнесенных весьма далеко относительно друг друга. В этом случае одного конференц-телефона явно будет недостаточно, поскольку хоть выносные микрофоны и могут помочь получить звук из разных точек зала, они не обладают динамиками, а значит не донесут до говорящего реакцию собеседника. Что же делать? Снова вспоминать о спикерфоне!

Естественно, на этот раз Snom C52-SP не будет основным устройством для работы со звуком, а лишь частью системы, основанной на C520-WiMi. Максимум в систему можно подключить до 3-х C52-SP, обеспечив хорошей слышимостью каждый уголок конференц-зала.

Итог

Мы поразмышляли над применением Snom С520-WiMi и C52-SP со своей точки зрения. Уверены, вы найдете устройствам для конференц-связи множество применений, а мы всегда будем рады помочь вам с их реализацией, предоставив качественные и функциональные средства связи для ваших задач.

Подробнее..

Привычный ужас в SIP, или о том, как не надо проектировать сетевые протоколы. Часть 1 синтаксис и морфология

22.03.2021 22:08:50 | Автор: admin

Здравствуйте, меня зовут Валентин, и я задолбался. Нет-нет, вы всё ещё на Хабре.

Все технологии телефонии ужасны.
Большинство технологий разработки IETF ужасны. Может, не ужасны-ужасны, как ISO
Когда они смешиваются ну вы в курсе. Или ещё нет? Получается SIP.


Это пост ворчания, техническая суть которого может быть полезна паре сотен человек. Но, to grumble is human.





Начнём с синтаксиса



HTTP заголовок видели все. Ну, большинство. Кто не видел может посмотреть на заголовок почтового письма (email). Принципы взяты оттуда, НО...



Я буду брать примеры из стандартных RFC, чтобы не влияла местная специфика. Типичное сообщение выглядит в таком стиле:



INVITE sip:bob@biloxi.example.com SIP/2.0
Via: SIP/2.0/TCP client.atlanta.example.com:5060;branch=z9hG4bK74bf9
Max-Forwards: 70
From: Alice <sip:alice@atlanta.example.com>;tag=9fxced76sl
To: Bob <sip:bob@biloxi.example.com>
Call-ID: 3848276298220188511@atlanta.example.com
CSeq: 1 INVITE
Contact: <sip:alice@client.atlanta.example.com;transport=tcp>
Content-Type: application/sdp
Content-Length: 151

v=0
o=alice 2890844526 2890844526 IN IP4 client.atlanta.example.com
s=-
c=IN IP4 192.0.2.101
a=sendrecv
t=0 0
m=audio 49172 RTP/AVP 0
a=rtpmap:0 PCMU/8000


Alice инициирует звонок к Bob (полные адреса указаны в виде user@domain), предлагая аудио в кодеке PCMU (G.711u) и сообщая свои адреса (хост: порт) для сигнализации и для медии.

Пойдём вглубь

Параметры, параметры и параметры



У нас есть address parameters, URI parameters и user parameters. Не то чтобы это был необходимый набор для работы, но если начал, становится трудно остановиться Все три отделяются точками с запятой, ограничения на синтаксис у всех немного разные. Смотрите не перепутайте. Кстати, чем отличается адрес от URI, тоже не каждому сразу получится объяснить. Адрес (определение формально не встречается в спеках, но постоянно используется на практике) это содержимое всяких From/To/Contact/Route (один элемент, где их несколько), URI с параметрами и (возможно) именем Ну поехали:



To: sip:bob@example.com
тут всё просто схема, домен и юзер.


To: sip:bob@example.com;xyz=123
xyz=123 параметр адреса. Но: если URI должен присутствовать сам по себе, как в первой строке запроса:

INVITE sip:bob@example.com;xyz=123
то xyz=123 будет уже параметром URI.

To: <sip:bob@example.com>;xyz=123
To: "Bob" <sip:bob@example.com>;xyz=123
xyz=123 параметр адреса.

To: <sip:bob@example.com;xyz=123>;xyz=456
xyz=123 параметр URI.
xyz=456 параметр адреса.

To: sip:bob;rn=alice@example.com;xyz=987
Так нельзя. Странно, да? Хотя если URI там, где нужен именно URI (в request line), то можно:
INVITE sip:bob;rn=alice@example.com;xyz=987 SIP/2.0

Надо заключить в угловые скобки:

To: <sip:bob;rn=alice@example.com;xyz=987>;xyz=123
rn=alice параметр юзера.
xyz=987 параметр URI.
xyz=123 параметр адреса.


Кстати, во всех допускаются символы за пределами очевидного набора типа [A-Za-z0-9] и ещё некоторого набора неожиданно допущенных, но по-разному. В user и в URI надо квотить недопустимое их кодами через %XX, а в адресе через quoted string, и никак иначе. Поэтому параметр со значением a%\b будет передан:


To: <sip:bob;xyz=a%25%5Cb@example.com;xyz=a%25%5Cb>;xyz="a%\\b"

В спеке на синтаксис, обобщение для параметра URI зовётся other-param, а параметра адреса generic-param. Смотрите не перепутайте, правила для них заметно разные. Кстати, user parameters это другая спека (точнее, произведение двух RFC4694 + RFC3398).


Что может быть значением параметра URI? Что угодно, только надо его единообразно заквотить (через %XX), дальше это набор октетов (UTF-8, если в SIP). Примеры были выше.


Что может быть значением параметра адреса? token, quoted string или host. Кстати, token это не token в смысле грамматического разбора. Это особый token, которого лично зовут token. Но при этом с маленькой буквы, потому что он самый скромный token.


To: <sip:bob@example.com>;xyz=127.0.0.1

127.0.0.1 это host или token? Допустимы оба. Должен ли я считать, что это host?

To: <sip:bob@example.com>;xyz=[fe80::1]
To: <sip:bob@example.com>;xyz="[fe80::1]"

Значения одинаковы. Но в первом случае это host подтипа IPv6reference,
во втором quoted string. Если я прокси и передаю параметр через себя, я должен сохранить, чем он был восстановление по содержимому не поможет.


Кстати, к предыдущему примеру:



To: <sip:bob@example.com>;xyz="127.0.0.1"

это не host и не token. Но если объекту типа address скажут назначить параметр со значением "127.0.0.1" какой тип выбрать? Ах ну да, такая установка уже должна указывать тип...


Вместе с тем, что если это token, то регистр букв не имеет значение, а если quoted-string, то имеет; а если host, то снова не имеет для адекватности одновременно обработки и сохранения исходного значения (про регистр подробнее ниже) я должен хранить:


1) Исходную форму как октетную или unicode строку для точного воспроизведения;
2) Приведённую форму для сравнения;
3) Признак, какого типа был параметр на входе (насколько это вообще восстановимо, не зная по названию параметра, чем он должен быть хотя годится обобщение типа любой host кроме IPv6reference может храниться как token там ещё есть несколько подобных тонкостей).


Но в To допускается только один адрес. А в Contact несколько. Есть некоторые другие поля заголовка, где тоже можно, но пока пусть например будет слонёнок Contact:

Contact: sip:alice@example.com, sip:bob@example.com

Да, можно.


Contact: <sip:alice@example.com>, sip:bob@example.com, <sip:mallory@example.com>

Тоже можно.


Contact: sip:alice,bob@example.com

Нельзя. URL с запятой должен быть заключён в <>. Распарситься не должно: после запятой нет схемы URL.


Contact: sip:alice, bob bob bob <bob@example.com>

Уже можно. Хотя это надо минимум три синяка от граблей, чтобы сразу видеть, что alice уже не юзер, а домен.


Contact: sip:alice,bob@example.com, sip:mallory@example.com

Нельзя. URL с запятой внутри поля заголовка конструкции адрес должен быть заключён в <>.


Contact: <sip:alice,bob@example.com>, sip:mallory@example.com

Уже можно. При этом второй адрес заключать не обязательно.


Хорошо, а это что тогда?


Contact: sip:alice,sip:bob@example.com

Это два адреса в контактах: sip:alice (alice это хост, user отсутствует целиком) и sip:bob@example.com. Но:


Contact: <sip:alice,sip:bob@example.com>

Это один адрес с user=alice,sip и паролем bob. Да-да, запятая в user возможна и её можно не квотить.


Это я ещё не вспоминал, что впереди может быть display-name, а позади адресные параметры:


Contact: sip user <sip:alice>, "The Bob" <sip:bob@example.com>;
foo="The Bob, Almighty and Superb <sip:bob>", <tel:alice;xyz=987>


И снова здравствуйте, меня зовут Валентин. (Здравствуй, Валентин ответил нестройный хор.) Я сделал реализацию разбора SIP регулярными выражениями, и нет, я не стыжусь этого. У меня нет проблем, которые нельзя так решить: в грамматике нет рекурсии (максимум есть списки), и, к счастью, это единственное, что там хорошее. Если бы была рекурсия разбор был бы ужасен-ужасен. А так, он просто ужасен:


>>> len(SipSyntax.re_addr)
2847

Нет, мне не страшно. Потому что эти выражения формируются из отдельных частей:


re_addr = "(?:%s|%s)%s?" % (re_name_addr, re_addr_spec_short, re_gen_params_wsc)

и на каждом этапе я могу проверить качество каждого выражения и соответствие правилам комбинирования. Кстати, некоторые мелочи, которые никогда за почти 20 лет существования продуктового стека не понадобились (типа возможности absoluteURI), тут не реализованы. С ними было бы ещё в полтора раза больше, наверно.


Но почему таки регулярные выражения? спросит отдельный робкий голос. Ответ: а потому что Python.


Я сравниваю один и тот же разбор URI на Python через regexps, Java через regexps и Java через пропуск по классам символов. Сравнение эффективности на одной и той же железке (Ryzen5):


CPython + regexps        - 14K/secPyPy    + regexps        - 130K/secJava    + regexps        - 270K/secJava    + symbol classes - 1800K/secPyPy    + symbol classes - 3K/sec

Всё потому, что в Python движок регулярных выражений написан на C, а обходить его означает выходить на уровень интерпретатора, который страшно медленный. Предкомпилированные (на этапе загрузки модулей парсинга) выражения превращаются в аккуратные таблички в памяти это хуже, чем выхлоп какого-нибудь re2c, но по ним бегает неплохо оптимизированный код матчинга. В Java вроде JIT, но движок регулярных выражений написан на самой Java, и JIT ему не очень помогает, когда логика состоит из сплошных переходов с лукапами по табличкам, которые этим JITом не перерабатываются. На чём-то напрямую компилируемом цифры могут быть ещё вкуснее нет, я не буду впадать в этот флейм. PyPy заметно помогает, но есть порог, за которым кончается и его умение (а цифры говорят, что >90% накладных расходов CPython это работа со структурами Python, а не собственно управление памятью, парсинг и т.п.)


Что такое лукап по классам символов это в таком духе:


        while (pos < limit && (b = source[pos]) >= 0 &&                SipSyntax.userinfo_allowed[b] != 0)        {            ++pos;        }

табличка userinfo_allowed тщательно выверена руками и подкреплена юнит-тестом.


(Меня удивила цифра PyPy, но, может, это я оказался такой криворукий. Но на CPython я даже не пытаюсь это делать страашно. Ладно, может, попробуем, как сады зацветут.)


А ещё есть проблема '#'. По RFC, такое не разрешено:


INVITE sip:123#456@example.com SIP/2.0
From: <sip:123#789@example.com>; tag=from1


но не только лишь все (tm), начиная с Cisco, это игнорируют. Поэтому почти сколько существует наш продукт, почти столько и существует параметр получателя url_hash_safe, который говорит рисовать #, а не %23 (а %23 многие из них не понимают). Но некоторые наоборот, не понимают, если ставить '#'. Поэтому нужна регуляция по конкретному ремотному участнику определять, кому таторы, а кому ляторы. Последний раз я подсказывал техподдержке включить этот параметр прошлой осенью. Наверно, эта проблема будет жить вечно. Ах да, '*' ещё один частый символ в этих последовательностях разрешён явно и проблемы не вызывает. Неаккуратненько-с.


В RFC3261 есть роскошное примечание:


The Contact, From, and To header fields contain a URI. If the URI contains a comma, question mark or semicolon, the URI MUST be enclosed in angle brackets (< and >). Any URI parameters are contained within these brackets. If the URI is not enclosed in angle brackets, any semicolon-delimited parameters are header-parameters, not URI parameters.

Спасибо, дорогая партия, за наше счастливое детство. У меня вопрос: а зачем вообще было разрешать вариант без угловых скобок? Ах да, забыл: в Route и Record-Route угловые скобки обязательны. В From, To, Contact нет. Картина Репина.



Почему не готовый движок парсинга?


Если упоминается Java, кто-то обязательно спросит почему не ANTLR?


Я пробовал применить ANTLR. Нет, конечно, это можно. Забитый молотком шуруп держится лучше, чем вкрученный отвёрткой гвоздь. В linphone его применяют. Но уже там видны недочёты.


Ему нельзя снаружи управлять контекстом для лексического анализатора, а это критично. Есть несколько разных стартовых контекстов: как минимум: первая строка сообщения, URI, адрес, ряд специфических заголовков со своими правилами (Call-Id, Authorization...)


Можно было бы справиться с semantic rules на месте, но:


  • Каждый парсер стартует со своим лексером.
  • Лексер не может получать указание по контексту от парсера, он должен определять это сам.
  • Контекстов очень много.

Часто однозначного решения нет. Начало адреса может присутствовать или схема с ':' (включать ли двоеточие в токен лексера?), или display-name как последовательность token (это не тот токен, это другой токен, который token в грамматике SIP). После схемы в SIP-URI или хост, или username, и различить их можно только по тому, что раньше встретится после него (может, заметно после него) '@', ';', '?' или EOI. Не так предсказал откат назад на другую гипотезу.


Начальных контекстов как минимум: начало адреса (одиночного или множественного поля заголовка типа From, To, Contact, Route, Record-Route...); начало URI (например, в первой строке SIP запроса). Есть ещё несколько специфических контекстов для авторизационных заголовков, например там целые URI могут находиться в кавычках. В результате, получается сплошное дублирование. Грамматики лексеров не могут включать другие грамматики лексеров (почему?) В результате чтобы избежать копипастинга надо генерировать грамматики отдельным макропроцессором. Ну спасибо...


Альтернативно, можно было бы на уровне лексера определить каждый символ, а выше собирать их уже в грамматические конструкции. Исключение даётся только для quoted-string (и то за пределами авторизационных заголовков). Но производительность падает на порядки, реализация на Java становится тормознее реализации на Python+regexps.


Поэтому доступные реализации невозможно читать без ящика водки. Виски не подойдёт: он для добавления положительных эмоций, а не гашения отрицательных. Если бы не требование менять контексты лексера из самого лексера, было бы ещё подъёмно (LL() превратился бы в цивилизованный PEG), но не как сейчас.


Вместо регулярных выражений можно использовать классы символов. И на компилируемом языке это быстрее (ускорение раз в 5 я получаю без оптимизационных ухищрений). Но не на Python: его движок регулярных выражений на C, а поиск по строке будет чудовищно дорог.


В целом, мир грамматики IETF выглядит сущностью, принципиально противоположной тому, что рекламируется, например, в Dragon Book. Возможно, для него нужна своя теория, которая будет заметно отличаться от знаменитых LL(k), LR(k) и прочих. Но я такого не видел.


И ложка мёда:


А знаете, что хорошо по сравнению с RFC822, например? Границы строк чётко определены. Кошмариков типа "\\\r\n", которое неверно разбирали 99% почтовых парсеров, уже нет. Поэтому я могу (и даже обязан) сначала опознать границы строк, по ним полей заголовка, и тогда каждый подавать на разбор уже по своему вкусу (а скорее всего вообще не подавать те, что не нужно).


За 17 лет (1982->1999) IETF кое-чему научился. Жаль, что это так медленно происходит.



Морфология


У нас в каждом сообщении нужно посылать From и To. На INVITE выше приходит ответ, например:


SIP/2.0 100 TryingVia: SIP/2.0/TCP client.atlanta.example.com:5060;branch=z9hG4bK74bf9    ;received=192.0.2.101From: Alice <sip:alice@atlanta.example.com>;tag=9fxced76slTo: Bob <sip:bob@biloxi.example.com>Call-ID: 3848276298220188511@atlanta.example.comCSeq: 1 INVITEContact: <sip:bob@client.biloxi.example.com;transport=tcp>Content-Length: 0

Реально они нужны только в одном виде сообщений в начальном для установления диалога (или в отдельной транзакции). Дальше их можно тупо выкидывать, от этого ничего не поменяется: на них ничего не завязывается и никто не парсит, хотя пропускать их запрещено. Матчинг ответов на транзакции происходит по h_Via.branch. Матчинг ответов внутри диалога происходит по тегам диалога. И снова, смотрите не перепутайте. Я сам путаюсь, когда через несколько месяцев не-общения с этим всем возвращаюсь к тематике.


Так зачем же нужны эти From и To? А затем, что там теги.


From: Alice <sip:alice@atlanta.example.com>;tag=9fxced76sl
To: Bob <sip:bob@biloxi.example.com>;tag=skfhjskdkfsd

Ах да, я ж забыл упомянуть теги:


У нас есть call-id и есть два тега. Вместе они образуют полный идентификатор диалога (ассоциация между двумя конечными участниками). Сообщение внутри диалога (у него два тега) определяет модификацию установленного звонка, а вне диалога (только один тег) новый звонок. (Я упростил всё, что можно, но для первого описания пойдёт.)


Call-id имеет особые, ни на что остальное в SIP не похожие, правила допуска и сравнения. Он регистрозависим (в отличие от тегов диалога), но об этом ниже. У него свой набор допустимых символов. Call-id неуникален, его совпадение у соседних звонков норма и закономерность (при форкинге диалога, когда на один запрос отвечают несколько удалённых участников). В отличие от, теги диалога уникальны, требуется хотя бы 32 бита случайности при их генерации, больше лучше. На самом деле после генерации тегов call-id вообще не нужен, у него роль мнэээ в рамках стандартных использований по RFC у него роли вообще нет, кроме как путаться под ногами, всё работало бы и без него. А вот для B2BUA, как у нас, call-id начинает выполнять особую функцию связи между звонками на разных сторонах одного B2BUA. Но B2BUA не определён ни одним RFC даже в ранге informational; это такое странное понятие, на которое ссылаются в нескольких RFC, но определено в лучшем случае неформально.


Так почему теги не в отдельных полях заголовка? Вы не найдёте обоснованного ответа на этот вопрос: это уже закон жизни, который тайна веков. Но зато ради них приходится полностью парсить целые From и To, с учётом всех тонкостей по содержанию (см. выше про адресные поля).


Cинтаксис возвращается: регистр букв


По непонятной прихоти call-id регистрозависим, а теги нет. Точнее, так в книге написано (tm), что они регистронезависимы. Реально же:
1) Есть UA (user agents железные или программные телефоны), которые воспринимают посылки в диалоге только если буквы в теге в том же регистре, что они посылают (если это Abc, то и надо прислать им Abc).
2) Есть UA, которые переделывают теги под себя, и если им прислать abc они ответят ABC. Или наоборот, прислали ABC а они отвечают abc.


И с обоими надо работать. Отказывать просто потому, что они нарушают ну в основном нельзя. Потому что всё равно не исправят большинство из них железные, и авторы прошивки просто не поймут, чего от них хотят. Не знаю, зачем производители железных UA нанимают таукитян или сентинельцев? Сложно разобрать, но проверено, что планета у них какая-то другая.


Какой вариант работает в итоге? Тег надо хранить в двух вариантах: приведённый к конкретному регистру для сравнения, и неприведённый для посылки другому участнику. Где-то мы это уже слышали?


И то же оказалось привет, история в Git с transport параметром URI. Потому что мы добрые, и если чужой телефон или SBC настаивает, что должно быть transport=UDP, а не transport=udp, то легче согласиться, чем спорить. Это карма авторов чисто софтового продукта: легче адаптировать софт, чем даже прошивку железного аппарата (а тем более само железо).


Но это были цветочки, основной же вопрос зачем вообще эта регистронезависимость?


Стандартные аргументы в пользу регистронезависимости: облегчение человекочитаемости. Это миф: её путают с человекоозвучиваемостью. Регистр не должен быть важен, например, в имени человека (хотя и тут могут быть тонкости). Но я не знаю, в каком случае с экрана будет читаться что-то в шрифтах, которые не различают регистр. И совсем не понимаю, почему и зачем различие регистра считается важнее, чем 100500 других различий.


Этот тезис можно обсудить в применении, например, к файловым системам отдельно (почему такие FS различают foo.docx, foo.docx , foо.docx и foo.docx (кто увидит разницу?), но не различают foo.docx и Foo.docx?), и что будет в случае (см. Turkey test), но сейчас речь не о них, а о SIP на простом беспроблемном ASCII.


Вы можете написать:


<code>From: <sip:123@foobar>;tag=mamarama</code>

но вы можете также написать:


<code>fRoM      :  <sip:123@foobaR>;TaG=mamaRAMa</code>

Все воспринимающие должны понять это одинаково. Но чего этого стоит? Обратимся к коду одной из самых быстрых реализаций Kamailio, в девичестве Sip Express Router.


/*! \brief macros from parse_hname2.c */#define READ(val) \(*(val + 0) + (*(val + 1) << 8) + (*(val + 2) << 16) + (*(val + 3) << 24))#define LOWER_DWORD(d) ((d) | 0x20202020)...#define _cont_ 0x746e6f63......                                // например возьмём этот кусок                                if ((LOWER_DWORD(READ(c)) == _cont_) &&                                        (LOWER_DWORD(READ(c+4)) == _ent__) &&                                        (LOWER_DWORD(READ(c+8)) == _type_)                                ) {                                        /* Content-Type HF found */

Ну, это хорошо работает на C. (Clang умудрился свернуть READ в просто 32-битное чтение из памяти. GCC этого не сумел. Ну не так страшно.) Уже на Java надо финтить, но хотя бы есть ByteBuffer. На интерпретаторах вроде Python, и на Java на строках, это превращается в чудовищную затрату или времени, или памяти, или обоих сразу.


Но и этот детект помогает только в очень ограниченной роли быстрый поиск по первым четвёркам символов (а ещё есть альтернативные имена полей f вместо from, i вместо call-id; пробелы до и после ':' в неограниченном количестве; и так далее). А как только мы выходим за пределы средств с прямым изменением в буферах привет, копирование.


Продолжение следует

Подробнее..

У меня зазвонил телефон. Кто говорит?.. Поможет слон

17.08.2020 16:16:01 | Автор: admin
Автоматическое определение клиента и его региона по входящему телефонному звонку стало неотъемлемой частью любой развитой HelpDesk или CRM-системы. Только надо уметь делать это быстро тогда появляется масса возможностей.

Например, можно менеджеру сразу показать из какого города идет звонок, подтянуть актуальный прайс и условия доставки, вывести карточку звонящего клиента, последние сделки с ним, конкретное контактное лицо, да много чего полезного, как это умеет наш СБИС CRM!


А как этот функционал реализовать самостоятельно? Оказывается, не так уж сложно. Собрать и опробовать работающую модель можно, буквально, на коленке нужна только связка из Node.js и PostgreSQL.

Определяем регион по номеру


Давайте предположим, что АТС присылает нам уже нормализованный и отформатированный до 10 цифр (будем рассматривать только звонки внутри России) входящий телефонный номер. Как наиболее эффективно понять, откуда пришел звонок?

Собираем телефонные коды


Сначала нам понадобится база телефонных кодов России в привязке к регионам. Для этого можно воспользоваться официальным источником актуальной выпиской из плана нумерации на сайте Федерального агентства связи.

Но найти мало, надо эти данные скачать и извлечь. В этом нам поможет небольшой скрипт для Node.js, использующий библиотеку request:

const async = require('async')  , request = require('request');const fs = require('fs');let queue = [  'ABC-3xx', 'ABC-4xx', 'ABC-8xx', 'DEF-9xx']  .map(key => (    {      base : 'https://rossvyaz.gov.ru'    , path : `/data/${key}.csv`    }  ));let ranges = [];async.doWhilst(  cb => {    // берем из очереди и загружаем очередную страницу    let task = queue.shift();    request(      {        url  : task.base + task.path      , pool : false      }    , (err, res, body) => {        // примитивный разбор CSV        body.split('\n').forEach(line => {          let tds = line.split(';');          let place = tds[5].split('|');          ranges.push([            tds[0]          , tds[1]          , tds[2]          , tds[4]          , place[place.length - 1]          , place[place.length - 2] && place[place.length - 2].startsWith('р-н') ? place[place.length - 2] : ''          , place.length > 1            ? place[0].startsWith('р-н')              ? ''              : place[0]            : ''          ]);        });        return cb(err);      }    );  }  // итерируем, пока очередь заданий непуста, cb => {    return cb(null, queue.length);  }  // когда все распарсили - подчищаем данные и формируем файл для загрузки в БД, err => {    // чистим коды и диапазоны    ranges.forEach(row => {      // убираем пересечение цифр кода и диапазона      let ln = row[0].length + row[1].length - 10;      if (ln > 0) {        let sfx = row[0].slice(-ln);        if (row[1].startsWith(sfx) && row[2].startsWith(sfx)) {          row[1] = row[1].slice(ln);          row[2] = row[2].slice(ln);        }      }      // пересобираем общий префикс      let pfx;      for (let i = 1; i < row[1].length; i++) {        if (row[2].startsWith(row[1].slice(0, i))) {          pfx = row[1].slice(0, i);        }        else {          break;        }      }      if (pfx) {        row[0] = row[0] + pfx;        row[1] = row[1].slice(pfx.length);        row[2] = row[2].slice(pfx.length);      }    });    let sql = `SET client_encoding = 'UTF-8';CREATE TABLE phonecodes(  code    varchar, numb    varchar, nume    varchar, oper    varchar, region    varchar, district    varchar, city    varchar);COPY phonecodes FROM STDIN;`;    // собираем COPY-формат    let copy = ranges.map(row => row.join('\t')).join('\n') + '\n\\.\n';    fs.writeFileSync('phonecodes.sql', sql + copy);  });

Теперь загрузим его в нашу тестовую базу, и можно работать:

psql -f phonecodes.sql -U postgres tst

Если все сработало как надо, в нашу таблицу будет загружено почти 378 тысяч диапазонов:

SETCREATE TABLECOPY 377937

Замечу, что в нашем примере и код, и граничные номера диапазона представлены строками. Да, их можно превратить в integer/bigint, но мы пока не будем этим заниматься. Тем более, что входящий номер телефона не всегда состоит только из цифр например, некоторые таксофоны могут сообщать свой номер с цифрой A.

Ищут пожарные, ищет милиция...


Сначала попробуем наивный запрос:

WITH src AS (  SELECT '4852262000' num -- входящий номер)SELECT  *FROM  src, phonecodesWHERE  num LIKE (code || '%') AND -- проверяем совпадение кода  num BETWEEN (code || numb) AND (code || nume) -- проверяем вхождение в диапазонLIMIT 1;


[посмотреть на explain.tensor.ru]

Вычитали почти 70 тысяч строк (и это еще повезло, что не все 380!), почти 10MB данных перелопатили не слишком эффективно, но результат достигнут:

num        | code   | numb | nume | oper | region           | district | city-----------------------------------------------------------------------------------4852262000 | 485226 | 0000 | 9999 | МТС  | Ярославская обл. |          | Ярославль

Но давайте как-то избавимся от Seq Scan! Для этого нам всего-то нужен индекс, который поможет искать по LIKE, так ведь?..

Увы, нет. Если нам надо искать column LIKE (val || '%'), то нам помогут префиксные индексы с varchar_pattern_ops, но у нас-то все наоборот val LIKE (column || '%'). И мы получаем ситуацию близкую к той, что я описывал в статье Классифицируем ошибки из PostgreSQL-логов.

Используем знания о прикладной области


Близкую, но, к счастью, все-таки существенно проще данные у нас фиксированы и их относительно немного. Причем по кодам записи распределены достаточно разреженно:

SELECT -- сколько кодов с таким кол-вом диапазонов  ranges, count(*)FROM  (    SELECT -- сколько диапазонов по каждому коду      code    , count(*) ranges    FROM      phonecodes    GROUP BY      1  ) TGROUP BY  1ORDER BY  1 DESC;

Только лишь около сотни кодов имеют по 10 диапазонов, а почти четверть вообще ровно один:

ranges | count--------------    10 |   121     9 |   577     8 |  1705     7 |  3556     6 |  6667     5 | 10496     4 | 12491     3 | 20283     2 | 22627     1 | 84453

Поэтому давайте проиндексируем пока только код. А раз все диапазоны одного кода нам понадобятся все вместе упорядочим нашу таблицу с помощью CLUSTER, чтобы записи лежали физически рядом:

CREATE INDEX ON phonecodes(code);CLUSTER phonecodes USING phonecodes_code_idx;

А теперь вспомним, что телефонный номер у нас состоит ровно (всего!) из 10 цифр, среди которых нам надо вычленить префиксный код. То есть наша задача спокойно решается простым перебором не более чем 10 вариантов:

WITH RECURSIVE src AS (  SELECT '4852262000' num), T AS (  SELECT    num pfx -- в качестве исходного "префикса" задаем весь номер  , NULL::phonecodes pc  FROM    srcUNION ALL  SELECT    substr(pfx, 1, length(pfx) - 1) -- "отщипываем" последнюю цифру  , (      SELECT        X      FROM        phonecodes X      WHERE        code = T.pfx AND -- проверяем полное совпадение префикса        (TABLE src) BETWEEN (code || numb) AND (code || nume) -- проверяем вхождение в диапазон      LIMIT 1    ) pc  FROM    T  WHERE    pc IS NOT DISTINCT FROM NULL AND -- ищем, пока ничего не нашли    length(pfx) > 2 -- ... и префикс еще может оказаться кодом)SELECT  (pc).* -- "разворачиваем" найденную запись диапазона в поляFROM  TWHERE  pc IS DISTINCT FROM NULL;


[посмотреть на explain.tensor.ru]

Нам потребовалось всего 5 обращений к индексу, чтобы найти искомый код. Выигрыш кажется микроскопическим в абсолютных цифрах, но мы получили снижение нагрузки в 150 раз относительно наивного варианта! Если вашей системе приходится обрабатывать десятки и сотни тысяч таких запросов в час экономия становится весьма солидной!
А можно делать еще меньше итераций по индексу если все коды заранее привести к классическому виду от 3 до 5 цифр. Правда, тогда возрастет количество диапазонов в каждом коде, и их фильтрация может добавить проблем.

Определяем клиента по номеру


Теперь давайте представим, что у нас уже есть таблица с клиентами, где записан подчищенный номер телефона убраны все скобки, дефисы, и т.п.

Но вот неприятность, далеко не все и них имеют код города то ли менеджеры ленятся забивать, то ли АТС так настроена, что присылает не полные, а внутригородские номера Как тогда найти клиента ведь поиск по полному соответствию уже не сработает?

АТС дает полный номер


В этом случае воспользуемся тем же переборным алгоритмом. Только отщипывать цифры будем не с конца номера, а с начала.

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

Безусловно, нам потребуется какая-то перекрестная проверка по другим реквизитам (адрес, ИНН, ...), чтобы не получилось ситуации, что из входящего номера мы отрезали код Москвы, а по оставшемуся 7-значному номеру нашли клиента из Санкт-Петербурга.

АТС дает городской номер


пришло от АТС      :     262000указано в карточке : 4852262000

Тут ситуация интереснее. Приращивать каждый возможный код к короткому номеру и пробовать искать мы не можем их слишком много. Взглянем на ситуацию с другой стороны буквально:

    reverse(262000) -> 000262reverse(4852262000) -> 0002622584

Оказывается, если развернуть строки с номерами, то задача превращается в обычный префиксный поиск, который легко решается с помощью индекса с varchar_pattern_ops и LIKE!

CREATE INDEX ON client(reverse(phone) varchar_pattern_ops);

SELECT  *FROM  clientWHERE  reverse(phone) LIKE (reverse($1) || '%');

А дальше, опять-таки перепроверяем дополнительную информацию из какого региона АТС нам прислала номер, к какому региону относится клиент.
Подробнее..

А я говорю, возьми Excel и позвони

01.04.2021 14:11:52 | Автор: admin

Voximplant, как и любая облачная платформа, предоставляет API, с помощью которого можно управлять пользователями, запускать звонки, просматривать их историю и логи и делать немало других полезных вещей. В принципе, практически всё, что можно настроить в панели управления, можно сделать и через API.

Но в современном мире иметь API недостаточно мало кто хочет формировать HTTP-запросы, передавать параметры, думать про правильную авторизацию. Поэтому мы предлагаем SDK для разных языков программирования: Python, PHP, C# и многих других. И кажется, что этого достаточно, чтобы сделать нашу платформу лёгкой в использовании для очень большой аудитории. Или всё-таки недостаточно?

Обратимся к статистике. По разным данным сейчас в мире насчитывается где-то 15-30 миллионов разработчиков цифра несомненно впечатляющая. Но, например, пользователей MS Excel в мире не менее 100 миллионов. Почему же они должны страдать? Ведь, будем честны, почти каждый из тех, кто хоть раз открывал Excel, явно ощущал недостаток возможностей по управлению коммуникационными платформами в этом без сомнения очень гибком программном продукте. Практически каждый день мы получаем на наш email сотни запросов, которые сводятся к очень простой просьбе: Я хочу звонить из Excel!. Однажды у окон нашего офиса даже выстроились люди с такими требованиями (видели фото выше?) Мы просто не могли оставаться в стороне.

Однако звонки это всё-таки слишком революционно, а главное, потребует установки дополнительных ActiveX-компонентов, что, безусловно, противоречит всем существующим и несуществующим политикам информационной безопасности, поэтому давайте начнём с более простой вещи SDK для работы с нашим API. Из средств разработки в Экселе доступен VBA, для него мы и создадим SDK.

Для того, чтобы выполнить API-запрос, необходимо:

  1. Сформировать URL и тело POST-запроса.

  2. Добавить аутентификационные параметры.

  3. Непосредственно выполнить запрос.

  4. Распарсить результат (в нашем случае это JSON).

Формируем URL и тело POST-запроса

Первая часть, казалось бы, самая простая: нужно просто закодировать параметры в URL-кодировку и склеить их. Но в стандартом VBA не предусмотрена URL-кодировка (позже мы поймём, почему). Ничего страшного, на просторах Интернета есть множество разных решений, выберем одно из них.

Public Function URL_Encode(ByRef txt As String) As String    Dim buffer As String, i As Long, c As Long, n As Long    buffer = String$(Len(txt) * 12, "%")     For i = 1 To Len(txt)        c = AscW(Mid$(txt, i, 1)) And 65535         Select Case c            Case 48 To 57, 65 To 90, 97 To 122, 45, 46, 95  ' Unescaped 0-9A-Za-z-._ '                n = n + 1                Mid$(buffer, n) = ChrW(c)            Case Is <= 127            ' Escaped UTF-8 1 bytes U+0000 to U+007F '                n = n + 3                Mid$(buffer, n - 1) = Right$(Hex$(256 + c), 2)            Case Is <= 2047           ' Escaped UTF-8 2 bytes U+0080 to U+07FF '                n = n + 6                Mid$(buffer, n - 4) = Hex$(192 + (c \ 64))                Mid$(buffer, n - 1) = Hex$(128 + (c Mod 64))            Case 55296 To 57343       ' Escaped UTF-8 4 bytes U+010000 to U+10FFFF '                i = i + 1                c = 65536 + (c Mod 1024) * 1024 + (AscW(Mid$(txt, i, 1)) And 1023)                n = n + 12                Mid$(buffer, n - 10) = Hex$(240 + (c \ 262144))                Mid$(buffer, n - 7) = Hex$(128 + ((c \ 4096) Mod 64))                Mid$(buffer, n - 4) = Hex$(128 + ((c \ 64) Mod 64))                Mid$(buffer, n - 1) = Hex$(128 + (c Mod 64))            Case Else                 ' Escaped UTF-8 3 bytes U+0800 to U+FFFF '                n = n + 9                Mid$(buffer, n - 7) = Hex$(224 + (c \ 4096))                Mid$(buffer, n - 4) = Hex$(128 + ((c \ 64) Mod 64))                Mid$(buffer, n - 1) = Hex$(128 + (c Mod 64))        End Select    Next    URL_Encode = Left$(buffer, n)End Function

Следующий нюанс передача даты и времени. В API Voximplant временные метки принимаются в UTC в формате YYYY-MM-DD hh:mm:ss. В Excel же дата и время хранятся без учёта часового пояса (на самом деле, в самой таблице они вообще хранятся как число с плавающей точкой). Поэтому нам придётся принимать дату/время из таблицы тоже UTC. Мы думаем, что все 100+ миллионов пользователей Excel знают, что такое UTC, и это не вызовет у них никаких вопросов.

Кстати, в VBA есть функция форматирования даты, и она даже работает, но весьма необычным образом. Интересующий нас формат даты описывается так: yyyy-mm-dd hh:mm:ss. То есть mm это либо месяц, либо минуты в зависимости от того, за чем оно следует: за hhили за yyyy (это не шутка, это даже в MSDN описано). В общем, если кто-то захочет вывести время без часов, придётся импровизировать.

Переходим к аутентификации

Здесь нас ожидает самое большое разочарование. Мы в Voximplant предлагаем нашим клиентам использовать JWT, что, конечно, весьма мудрёно, если выполнять запросы из консоли или браузера, но при использовании наших SDK это совершенно никак не усложняет жизнь разработчику. В то же время JWT обеспечивает крайне высокий уровень безопасности.

А что же VBA? К сожалению, разумно простого способа сформировать JWT-подпись просто не существует. Причина в том, что в VBA доступен фреймворк .NET версии 4.x, а функция RSA.ImportPkcs8PrivateKey, необходимая для загрузки приватного ключа из PKCS8, появилась только в .NET 5. Да и вообще, все .NET-разработчики используют для таких задач сторонние библиотеки.

Поэтому нам придётся ограничиться авторизацией с помощью статического API-ключа. Ведь, как известно, один из способов обработки риска информационной безопасности - принятие этого риска. Так и поступим. Ведь нам ну очень-очень нужен этот SDK.

Кадр из кинофильма Большой Лебовски (The Big Lebowski (1998), Polygram Filmed Entertainment, Working Title Films)Кадр из кинофильма Большой Лебовски (The Big Lebowski (1998), Polygram Filmed Entertainment, Working Title Films)

Выполняем запрос

Переходим к третьей части к выполнению самого запроса. Встроенных средств работы с HTTP в VBA нет (теперь понятно, почему нет и функции URL-кодирования, а зачем?).

Но, тем не менее, это достаточно тривиальная манипуляция подключаем необходимый фреймворк MSXML 6.0 и Microsoft Scripting Runtime и выполняем запрос, подключая через COM сам MSXML. Просто!

Function makeRequest(name As String, params As Dictionary, accountId As Integer, apiKey As String) As Object    Dim objHTTP As New MSXML2.XMLHTTP60    Dim jsonData As String    Dim parsedJson As Object    Dim postString As String    postString = ""        Dim iterKey As Variant        For Each iterKey In params.Keys        postString = postString & "&" & iterKey & "=" & URL_Encode(params(iterKey))    Next    Url = "https://api.voximplant.com/platform_api/" + name    objHTTP.Open "POST", Url, False    objHTTP.send "account_id=" & accountId & "&api_key=" & apiKey & postString    jsonData = objHTTP.responseText    Set parsedJson = JsonConverter.ParseJson(jsonData)    Set makeRequest = parsedJsonEnd Function

Парсим JSON

Ну и, наконец, JSON. Как и всё остальное, парсер JSON надо искать где-то вовне экосистемы VBA. К счастью, на дворе 2021 год, есть GitHub, и кто-то уже озадачился созданием JSON-парсера для VBA. Мы взяли вот такой.

Он подключается как отдельный модуль и превращает JSON-строку в Dictionary. То, что нужно!

Дальше берём генератор одного из наших SDK (мы взяли питоновский), заменяем шаблоны и заставляем его генерировать код на VBA. В итоге получаем готовый SDK, который можно скачать на нашем GitHub.

SDK представляет собой Class Module, который можно подключить к вашей любимой книге в Excel и делать с его помощью разные странные вещи. В принципе, можно даже звонки запускать, SDK поддерживает все необходимые для этого функции API в). Но это будет не лучшей идеей, учитывая, что не до конца известно, когда Excel решит пересчитать все формулы (именно в этот момент произойдёт вызов функции API).

А вот для каких-то статистических задач SDK, несмотря на всю абсурдность происходящего, может подойти. Например, можно посчитать, какой из пользователей потратил на звонки больше всех денег за какой-то период.

Для этого пишем вот такую функцию:

Function getTotalCallCost(FromDate, ToDate, Username) As Double    Dim totalCost As Double    Dim lastCount As Integer    Dim offset As Integer    Dim res As Dictionary    Dim RecordsPerRequest As Integer    Dim api As New VoximplantAPI    totalCost = 0    lastCount = 1    offset = 0    RecordsPerRequest = 100        'Pass Voximplant account id and API key    api.SetCredentials 100, "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"        Do While lastCount > 0        Set res = api.GetCallHistory(FromDate, ToDate, remote_number:=Username, with_calls:=True, with_records:=True, with_other_resources:=True, offset:=offset, count:=RecordsPerRequest)                Dim session As Variant        Dim item As Variant                For Each session In res("result")            For Each item In session("calls")                totalCost = totalCost + item("cost")            Next            For Each item In session("records")                totalCost = totalCost + item("cost")            Next            For Each item In session("other_resource_usage")                totalCost = totalCost + item("cost")            Next        Next                lastCount = res("count")        offset = offset + RecordsPerRequest    Loop        getTotalCallCost = totalCostEnd Function

И вызываем её следующим образом:

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


Резюме:

При желании можно и для VBA сделать какое-то подобие SDK. При его создании не пострадал ни один разработчик. Ах да, с 1 апреля! :D

Подробнее..

ISDN. Цифровая телефония XX века

02.05.2021 12:15:03 | Автор: admin


Когда мы говорим цифровая телефония, то первым делом на ум приходит протокол SIP. Олды, вздрогнув, вспомнят про H.323 и танцы с бубном при его настройке на АТС абонента. И мало кто знает, что цифровая голосовая связь это не всегда VoIP. Далеко не всегда.

Скажу более, идея передачи голоса абонента телефонной сети в цифре и цифровой же обработки информации сетью была высказана еще в далёком 1959 году, а к середине 1970-х годов заработали первые мощные цифровые телефонные коммутаторы. Так, шаг за шагом рождалась легендарная технология ISDN, чей расцвет пришёлся на 80-90-е годы (а у нас в 90-е и начало 2000-х). Её стандарты по сей день являются эталонными в цифровой телефонии. И вы ещё неоднократно встретите приветы из той эпохи, настраивая карточки Digium или номерной план очередного Зойпера.


Как всё начиналось


Нужда в цифре появилась не на пустом месте. Аналоговая телефония не могла должным образом обеспечить ни приемлемое качество передачи голоса на большие расстояния, ни достаточно быструю и точную коммутацию каналов связи при лавинообразном росте числа подключённых абонентов. Телефонная сеть это по сути обеспечение возможности соединить каналом передачи голоса двух любых человек абонентов этой сети. Первое решение очевидное и невозможное соединить всех со всеми телефонными проводами. Второе поняв, что абоненты в основном молчат, отделить каналы от абонентов (рассчитав необходимое число каналов) и подключать их по мере надобности. Барышня, дайте Смольный! это как раз про это.

Когда барышень, вручную подключающих телефонные шнуры, стало не хватать, то их быстро заменили электромеханическими устройствами. Однако это отнюдь не могло решить проблем телефонной сети. Потому что устройства эти продолжали всего лишь давать длинный провод от абонента к абоненту со всеми вытекающими последствиями. С появлением первых ЭВМ довольно быстро стало понятно, что отличить 1 от 0 гораздо, гораздо проще, нежели разобрать шёпот абонента Alice среди хрипов умирающих конденсаторов. И заменить покрытые окислами лапки реле управляющими командами, летящими на субсветовой скорости тоже передовая идея.

Уже в начале 1960 годов в США для передачи цифровых данных между АТС стали применяться
линии T1. А к 1970 году их использование стало там повсеместным. Линия Т1 состояла из 24 каналов по 64 кбит/с, мультиплексируемых для передачи речи и данных. Кстати, и до сих пор кое где подключают выделенные линии T1 к примеру всего за $600 в месяц.

В январе 1976 года в Чикаго компанией Western Electric был продемонстрирован первый мощный цифровой коммутатор телефонных каналов 4ESS. Его разработка началась в 1970 году в Лабораториях Белла, а последняя инсталляция случилась в 1999 году силами компании AT&T, преемницы Bell. На фотографии ниже инженер Билл Холланд тестирует отдельную секцию суперкоммутатора 4ESS:



ISDN расшифровывается как цифровая сеть интегрированных служб и первым делом как раз произошла интеграция передачи голоса и коммутации каналов этой самой передачи.

1980 году появился стандарт G.705, в котором излагались общие идеи такой сети. Конкретные спецификации сети ISDN появились в 1984 году в виде серии рекомендаций I, весьма противоречивой и приведшей, к примеру к различиям в реализации на практике (о чём чуть ниже). В 1988 году рекомендации серии I были пересмотрены и приобрели более детальный и законченный вид, хотя некоторые неоднозначности сохранились.

Рядовым пользователям сети ISDN она открывается своими интерфейсами передачи данных: BRI и PRI. Эти аббревиатуры знакомы уже многим. Интерфейс BRI подразумевает интегрированную линию, в которую входит канал передачи пакетизированных данных (D-канал) для управления соединением и два канала по 64 кбит/с для собственно, данных, например, закодированного звука. И кодек тот был придуман в 1988 году и звался G.711 (в двух модификациях A-law и U-law). Интерфейс PRI помимо бессменного D-канала поддерживает 30 (европейский стандарт E1) или 23 (японский/американский стандарт T1) B-каналов. Таким образом, например, линия E1 это уже весомые 1,875 Мбит в секунду. На дворе был 1990 год.

Умное железо


Не забываем, что сеть ISDN это про данные вообще, а не только про телефонию. Что закодировали, то и передают. Например, видео (1992 год, аппарат AT&T):

А вот, например, довольно современный видеотелефон Siemens T-View 100 ISDN, подключаемый к АТС Siemens HiPath 11xx:

Глобальные протоколы WAN X.25 и FrameRelay тоже имеют отношение к ISDN и могут обеспечивать связь между оборудованием ISDN.

Но нас в первую очередь интересует телефония. Сколько раз мне приходилось слышать, что после перехода на SIP качество телефонной связи с городом в какой-либо конторе ухудшилось. Для меня это верный признак того что там от провайдера подходил поток PRI по отдельной линии, и стоит там АТС типа Samsung OfficeServ 100:

или даже Panasonic TDA 200:

И я их прекрасно понимаю. Сеть ISDN это сеть с коммутацией каналов. Поэтому, если канал занят телефонией, то под голосовой трафик гарантированно отдан весь канал и ни байтом меньше. Конечно, и в IP сети можно настроить приоритезацию и QoS, но можно ведь и не настроить

Именно в корпоративном сегменте ISDN телефония получила самое широкое распространение, и даже по сей день большинство из вас время от времени пользуется устройствами, работающими по одному из протоколов ISDN. Я в первую очередь говорю о проприетарных реализациях BRI и системных телефонах офисных АТС. Это которые обычно стоят на ресепшне, такие с лампочками, и с которых можно не только звонить, но и программировать АТС. Это счастье как раз и обеспечивается тем, что связь с АТС осуществляется по полноценному цифровому протоколу. Вот типичный представитель, Panasonic KX-T7630:

Лампочки BLF, такие удобные, уже перекочевали в новые SIP-телефоны.
Питание этих аппаратов идёт по тем же двум (!) проводам, что и передача голоса и данных. При очень большом желании к подобному аппарату можно пристыковать USB модуль, а к нему ваш ноутбук, например, подключившись тем самым ноутом к АТС. На расстоянии 200 метров от неё, например.

Также на основе плат с интерфейсами BRI можно развернуть наиболее качественный из доступных по цене тип микросотовой DECT связи на 100 человек и покрыв площадь целого учреждения. На уже приведённой ранее фотографии Panasonic KX-TDA200 есть и эти платы.
К ним подключаются такие вот базы:

через которые к АТС внезапно можно подключить даже некоторые модели бытовых DECT трубок.

Немного о телефонных номерах


ISDN это всё-таки сеть, а поэтому в ней возможна передача информации об абоненте и сквозная нумерация. Технология ISDN разрабатывалась как основа всемирной телекоммуникационной сети, позволяющей связывать как телефонных абонентов, так и абонентов других глобальных сетей компьютерных, телексных и пр. Поэтому при разработке схемы адресации узлов ISDN необходимо было:
  1. сделать эту схему достаточно емкой для всемирной адресации
  2. сделать её совместимой со схемами адресации других сетей, чтобы их абоненты в случае соединения своих сетей через сеть ISDN могли бы пользоваться привычными форматами адресов

Разработчики технологии ISDN (например, в отличии от разработчиков стека TCP/IP) решили добиться использования в адресе ISDN адресов объединяемых сетей.
Основное назначение ISDN это передача телефонного трафика. Поэтому за основу адреса ISDN был взят формат международного телефонного плана номеров, описанный в стандарте ITU-T E.163. Однако этот формат был расширен для поддержки большего числа абонентов и для использования в нем адреса других сетей, например Х.25. Стандарт адресации в сетях ISDN получил номер E.164. Знакомые символы, верно? Их вы можете увидеть, настраивая диалплан практически любого SIP телефона или софта.

Формат Е.163 предусматривает до 12 десятичных цифр в номере, а формат адреса ISDN в стандарте Е.164 расширен до 55 десятичных цифр. Это позволяет включить в набираемый номер донабор местного абонента (пресловутый добавочный 123) или вызове абонентов из сети, не относящейся к ISDN (я про ту же X.25) при помощи системы префиксов, описываемой стандартом ISO 7498.

Короче говоря, когда настраиваешь АТС-ку с E1/PRI самая большая возня именно с настройкой диалпланов. И это неспроста: после того, как всё правильно настроено, можно звонить откуда угодно куда угодно, и к тому же научить АТС переключать вызовы как по донабору звонящего абонента, так и в зависимости от прилетающей информации об этом самом абоненте. То есть в 1995 году Alice, заключив, например, контракт с Bob, могла уже звонить ему напрямую минуя ресепшн или голосовые меню. Просто набрав номер офиса Боба, даже без донаборов. Кто сказал CRM?

Большое плавание


Помимо обслуживание абонентов ISDN, разумеется, в полной мере обеспечивает коммутацию в глобальных масштабах для того и создавалась. В телефонных стойках местечковых и не очень провайдеров надолго расположилось оборудование операторского класса, например блок коммутации МР-256 АТС МТА М-200:

Эта железяка обеспечивает коммутацию 256 подключений Е1, в каждом из которых, напомню, 30 каналов. Хороший такой крупный опорно-транзитный узел можно из таких собрать.

С появлением стека TCP/IP и сетей на его основе появилась возможность разрывать линию передачи данных, обеспечивая прохождение трафика E1 через сети с пакетной коммутацией. Называется это интересное дело pseudowire и позволяет передавать PRI, например, даже через публичный (вплоть до мобильного) интернет по VPN туннелям. Ощущения, правда, странные. Обычно Е1 не любит такого насилия по отношению к себе и через некоторое время падает, до последнего сохраняя отменное качество передачи голоса.

С течением времени всё чаще проявляются именно минусы E1/PRI как то: дороговизна в обслуживании, низкая скорость передачи данных, сложности с масштабированием и отсутствие возможности добавлять поддержку новых услуг в протоколы. То ли дело новый SIP. Пропал пакет, да и пёс с ним UDP же, у меня джиттер ого-го какой Элис дозвонится до Боба вовремя*. Так что в дальнейшем цифровая телефония ХХ века останется лишь в заповедных углах транзитных узлов и многочисленных пасхалках внутри новых услуг связи.



Наши виртуалки можно использовать для разработки веб-сайтов.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!

Подробнее..

Распознавание эмоций в записях телефонных разговоров

21.06.2021 02:14:29 | Автор: admin

Технология распознавания эмоций в речи может может найти применение в огромном количестве задач. В частности, это позволит автоматизировать процесс мониторинга качества обслуживания клиентов call-центров.

Определение эмоций человека по его речи уже относительно насыщенный рынок. Я рассмотрела несколько решений от компаний российского и международного рынков. Попробуем разобраться, в чем их преимущества и недостатки.

1) Empath

В 2017 году был основан японский стартап Empath. Он создал платформу Web Empath, основанную на алгоритмах, обученных на десятках тысяч голосовых образцов японской медицинской технологической компании Smartmedical. Недостатком платформы является то, что она анализирует только голос и не пытается распознать речь.

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

Также важное влияние на форму проявления эмоционального состояния оказывают культурные и языковые особенности. И попытки многоязычной классификации эмоций демонстрируют значительное снижение эффективности их распознавания [1]. Тем не менее, такое решение имеет место быть, а компания имеет возможность предлагать свое решение клиентам по всему миру.

2) Центр речевых технологий

В составе программного продукта Smart Logger II компании ЦРТ есть модуль речевой аналитики QM Analyzer, позволяющий в автоматическом режиме отслеживать события на телефонной линии, речевую активность дикторов, распознавать речь и анализировать эмоции. Для анализа эмоционального состояния QM Analyzer измеряет физические характеристики речевого сигнала: амплитуда, частотные и временные параметры, ищет ключевые слова и выражения, характеризующие отношение говорящего к теме [2]. При анализе голоса первые несколько секунд система накапливает данные и оценивает, какой тон разговора был нормальным, и далее, отталкиваясь от него, фиксирует изменения тона в положительную или отрицательную сторону [3].

Недостатком такого подхода является неверное определение нормального тона в случае, когда уже в начале записи речь имеет позитивный или негативный эмоциональный окрас. В таком случае оценки на всей записи будут некорректными.

3) Neurodata Lab

Компания Neurodata Lab разрабатывает решения, которые охватывают широкий спектр направлений в области исследований эмоций и их распознавания по аудио и видео, в том числе технологии по разделению голосов, послойного анализа и идентификации голоса в аудиопотоке, комплексного трекинга движений тела и рук, а также детекции и распознавания ключевых точек и движений мышц лица в видеопотоке в режиме реального времени. В качестве одного из своих первых проектов команда Neurodata Lab собрала русскоязычную мультимодальную базу данных RAMAS комплексный набор данных об испытываемых эмоциях, включающий параллельную запись 12 каналов: аудио, видео, окулографию, носимые датчики движения и другие о каждой из ситуаций межличностного взаимодействия. В создании базы данных приняли участие актеры, воссоздающие различные ситуации повседневного общения [4].

На основе RAMAS с помощью нейросетевой технологии компания Neurodata Lab создала решение для контакт-центров, позволяющее распознавать эмоции в голосе клиентов и рассчитывать индекс удовлетворенности обслуживанием непосредственно во время разговора с оператором. При этом анализ осуществляется как на голосовом уровне, так и на семантическом, при переводе речи в текст. Система также учитывает дополнительные параметры: количество пауз в речи оператора, изменение громкости голоса и общее время разговора.

Однако стоит заметить, что база данных для обучения нейронной сети в данном решении была подготовлена специально с участием актеров. А, согласно исследованиям, переход от модельных эмоциональных баз к распознаванию эмоций в спонтанной речи ведет к заметному снижению эффективности работы алгоритмов [1].

Как видим, у каждого решения есть свои плюсы и минусы. Попробуем взять от аналогов все самое лучшее и реализовать собственный сервис для анализа телефонных звонков.

Empath

ЦРТ

Neurodata Lab

Разрабатываемый сервис

семантический анализ

-

+

+

+

русский дата-сет

-

нет

+

+

дата-сет спонтанных эмоций

+

-

+

В качестве материалов для создания русскоязычного эмоционального дата-сета со спонтанной речью мне была предоставлена база записей телефонных разговоров от IT-компании Эм Си Арт.

Общий алгоритм работы разрабатываемого сервиса выглядит следующим образом.

Блок-схема алгоритма обработки звонкаБлок-схема алгоритма обработки звонка

При реализации были использованы следующие инструменты:

  1. Шумоочистка RNNoise_Wrapper

  2. Диаризация pyAudioAnalysis

  3. Транскрибация vosk-api

  4. Анализ эмоций текста dostoevsky

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

Для работы со звуковой волной нужно сначала преобразовать ее в цифровой вид. Для этого выполняется процедура дискретизации, после которой будет получен массив чисел, каждое из которых представляет амплитуду звуковой волны через фиксированные промежутки времени. Обучение нейронной сети на этих данных было бы неэффективно, так как их объем очень большой. Чтобы решить данную проблему, можно выполнить преобразование сигнала в набор акустических характеристик. Для этого я использовала библиотеку Librosa.

Я выбрала пять наиболее часто используемых признаков:

  • мел-частотные кепстральные коэффициенты (MFCC)

  • вектор цветности

  • мел-спектрограмма

  • спектральный контраст

  • тональный центроид (Tonnetz)

На основе выделенных из записей телефонных разговоров отрезков я составила 3 варианта дата-сетов с различным количеством выделяемых классов эмоций. Также для сравнения результатов обучения была взята берлинская база эмоциональной речи Emo-DB, созданная с привлечением профессиональных актеров.

Сначала я попробовала обучить простые классификаторы библиотеки scikit-learn:

  • SVC

  • RandomForestClassifier

  • GradientBoostingClassifier

  • KNeighborsClassifier

  • MLPClassifier

  • BaggingClassifier

В результате обучения на дата-сете Emo-DB получилось достичь точности распознавания 79%. Однако при тестировании полученной модели на размеченных мной записях телефонных разговоров, точность оказалась равной всего 23%. Это подтверждает тезисы о том, что при многоязычной классификации и переходе от модельных эмоций к спонтанным точность распознавания значительно снижается.

На составленных мной дата-сетах получилось достичь точности 55%.

База данных

Количество классов

Количество записей

Модель

Точность

Emo-DB

4

408

MLPClassifier

79.268%/22.983%

MCartEmo-admntlf

7

324

KNeighborsClassifier

49.231%

MCartEmo-asnef

5

373

GradientBoostingClassifier

49.333%

MCartEmo-pnn

3

421

BaggingClassifier

55.294%

При увеличении количества выделяемых классов эмоций точность распознавания падала. Это так же может быть связано с уменьшением выборки ввиду сложности разметки по большому количеству классов.

Далее я попробовала обучить сверточную нейронную сеть на дата-сете MCartEmo-pnn. Оптимальной архитектурой оказалась следующая.

Точность распознавания такой сети составила 62.352%.

Далее я провела работу по расширению и фильтрации дата-сета, в результате чего количество записей увеличилось до 566. Модель заново была обучена на этих данных. По итогу точность распознавания увеличилась до 66.666%. Это говорит о необходимости дальнейшего расширения набора данных, что приведет к увеличению точности распознавания эмоций по голосу.

График истории обучения и матрица ошибок полученной CNNГрафик истории обучения и матрица ошибок полученной CNN

При проектировании сервиса была выбрана микросервисная архитектура, в рамках которой создается несколько независимых друг от друга узко сфокусированных сервисов, решающих только одну задачу. Любой такой микросервис можно отделить от системы, и дописав некоторую логику, использовать как отдельный продукт.

Сервис Gateway API производит аутентификацию пользователей по стандарту JSON Web Token и выполнять роль прокси-сервера, направляя запросы к функциональным микросервисам, находящимся в закрытом контуре.

Разработанный сервис был проинтегрирован с Битрикс24. Для этого было создано приложение Аналитика речи. В понятиях Битрикс24 это серверное приложение или приложение второго типа. Такие приложения могут обращаться к REST API Битрикс24, используя протокол OAuth 2.0, а также регистрировать свои обработчики событий. Поэтому достаточно было в сервере добавить роуты для установки приложения (по сути регистрация пользователя), удаления приложения (удаление аккаунта пользователя) и обработчик события OnVoximplantCallEnd, который сохраняет результаты анализа записей в карточках связанных со звонками CRM-сущностей. В качестве результатов приложение добавляет расшифровку записи к звонку и комментарий с оценкой успешности разговора по пятибалльной шкале с прикреплением графика изменения эмоционального состояния по каждому участнику разговора.

Заключение

В работе представлен результат исследования на тему распознавания эмоций в речи, в ходе которой на основе русскоязычных записей телефонных разговоров был создан дата-сет эмоциональной речи, на котором была обучена CNN. Точность распознавания составила 66.66%.
Был реализован веб-сервис, с помощью которого можно выполнять очистку аудиозаписей от шума, диаризацию, транскрибацию и анализ эмоций в аудиозаписи или текстовых сообщениях.
Сервис был доработан, чтобы его также можно было использовать как приложение Битрикс24.

Данная работа выполнялась по заказу компании Эм Си Арт в рамках ВКР бакалавра образовательной программы "Нейротехнологии и программирование" университета ИТМО. Также по этой теме у меня был доклад на X КМУ и была принята на публикацию в "Сборнике трудов Конгресса" статья.

В ближайшее время планируется работа по улучшению точности распознавания эмоций по голосу через расширение набора данных для обучения нейросети, а также замена инструмента диаризации, так как качество его работы на практике оказалось недостаточно хорошим.

Список источников

  1. Давыдов, А. Классификация эмоционального состояния диктора по голосу: проблемы и решения / А. Давыдов, В. Киселёв, Д. Кочетков // Труды международной конференции "Диалог 2011.". 2011. С. 178185.

  2. Smart Logger II. Эволюция систем многоканальной записи. От регистрации вызовов к речевой аналитике [Электронный ресурс]. Режим доступа: http://www.myshared.ru/slide/312083/.

  3. Smart logger-2 не дремлет. Эмоции операторов call-центров и клиентов под контролем [Электронный ресурс]. Режим доступа: https://piter.tv/event/_Smart_logger_2_ne_drem/.

  4. Perepelkina, O. RAMAS: Russian Multimodal Corpus of Dyadic Interaction for Studying Emotion Recognition / O. Perepelkina, E. Kazimirova, M. Konstantinova // PeerJ Preprints 6:e26688v1. 2018.

Подробнее..

Программные IP-АТС, E1, DSS-1 и нагрузочное тестирование

15.07.2020 22:07:35 | Автор: admin
Всем доброго вечера! Сегодня я решил написать про тестирование протокола DSS-1 в IP-АТС, начнем как всегда с теории, рассмотрим преобразования сообщений из SIP в DSS-1, поговорим про анализаторы протоколов и закончим нагрузочным тестированием.

Введение
Как говориться без теории никуда, хоть информации о потоке E1 и протоколе DSS-1 предостаточно, опишу основные моменты, которые важны для понимания дальнейшего материала.
Протокол DSS-1 имеет три уровня.
Первый уровень физический, отвечает за непосредственно установление физического соединений и формирование каналов PRI и BRI. Basic Rate Interface (BRI) содержит 2 B канала 64 кбит/с и один D-канал 16 кбит/с, Primary Rate Interface (PRI) содержит 30 B каналов 64 кбит/с и 2 D-канала 64 кбит/с. B-каналы передают голос, данные, в то время как D-каналы являются сигнальными. Один из каналов сигнализации служит для синхронизации оконечного оборудования, другой для передачи данных об устанавливаемых соединениях.
Второй уровень канальный, на данном уровне работает протокол Link Access Protocol D Channel (LAPD) спецификация Q.921. Протокол LAPD отвечает за формирование логических каналов. Соответственно после установлении физического соединения должно установиться логическое: NETWORK посылает сообщение SABME (Set Asynchronous Balanced Mode Extended, установить расширенный асинхронный режим), CPE отвечает сообщением UA (Unnumbered Acknowledge, ненумерованное подтверждение) для синхронизации. После этого между устройствами NETWORK и CPE должен постоянно поддерживаться обмен RR (Receiver Ready, приемник готов) и устанавливаются логические каналы D и B.
Третий уровень сетевой, на данном уровне у нас ходит сигнализация протокол Q.931, который передается в канале D и данные протокола Х.25, передаются в канале B.

SIP в DSS-1
Теперь, когда мы разобрались, как работает протокол DSS-1, рассмотрим, как происходит преобразование протокола SIP в EDSS-1 и обратно. На рисунке 1 показано стандартное установление соединения. Как мы видим из рисунка сообщения протокола SIP и DSS-1 похожи.


Рисунок 1 Преобразование SIP в DSS-1

Анализ потока E1
Теперь поговорим, как нам анализировать поток E1. Про физику потока его форму импульса мы говорить не будем, нас интересует исключительно логика. На моей практике было и такое, что две АТС отлично работают по E1 и только подключив анализатор протоколов мы видели ошибки.
Анализатор нам нужен для отображения сообщений протоколов второго и третьего уровня, с помощью него мы увидим потерю сигнала, срыв синхронизации и многое другое. Естественно с одной стороны мы ставим нашу АТС, с другой желательно устанавливать серийную АТС, ловить ошибки на ошибки нам не надо.
Для анализа протоколов нам может пригодится Linkbit AnyTest AT1000 или Asterisk + T1/E1 (PRI) Digital Card.

Linkbit AnyTest AT1000
Немного расскажу о Linkbit, по сути это аппаратно-программный комплекс, являющийся анализатором протоколов цифровой телефонии. Представляет собой приставку с интерфейсами, которая подключается по usb к компьютеру с установленным программным обеспечением. Поддерживает большое количество протоколов и кодеков, в том числе и интересующих нас DSS-1 и SIP.
На рисунке 2 показан графический интерфейс. В графическом интерфейсе отображается окно с расшифровкой сообщений DSS-1 и LAPD, при необходимости можно отключить отображение сообщений не интересующего протокола. Ниже отображается поток E1 c тайм-слотами, как мы видим на рисунке 2 у нас заняты 10 тайм-слотов (отображены зеленым), 3 освободились (отображаются черным), стоит отметить, что при нажатии на занятый тайм-слот мы можем прослушать разговор.


Рисунок 2 Анализатор протоколов Linkbit AnyTest AT1000

Asterisk + T1/E1 (PRI) Digital Card
Теперь поговорим о Asterisk, для работы нам понадобится T1/E1 (PRI) Digital Cards, которая устанавливается в слот PCI Express, соответственно немного придётся повозиться, что бы Asterisk увидел ее.
Заходим в отладку Asterisk и вводим команду pri debug span 1 (указали номер своего канала) и при входящем/исходящем мы будем видеть сообщение протокола DSS-1. Соответственно, что бы нам увидеть статус каналов мы можем воспользоваться командой pri show span 1. Если хочется увидеть сообщение LAPD, то следует воспользоваться командой pri intense debug span 1.


Рисунок 3 Отладка Asterisk: сообщения DSSS-1


Рисунок 4 Отладка Asterisk: отображение тайм-слотов

Нагрузочное тестирование
Вариант 1
Для проверки программной IP-АТС нам понадобится серийная IP-АТС, в разрыв потока E1 ставится Linkbit AnyTest AT1000, дальше используются генераторы трафика StarTrinity SIP Tester или Sipp. Сообщение протоколов анализируем с помощью Linkbit AnyTest AT1000.

Вариант 2
Для проверки программной IP-АТС нам понадобится серийная IP-АТС, в разрыв потока E1 ставится Linkbit AnyTest AT1000, дальше используются генераторы трафика StarTrinity SIP Tester или Sipp, которые осуществляют вызовы на Asterisk (Asterisk подымает трубку и заворачивает RTP). Сообщение протоколов анализируем с помощью Linkbit AnyTest AT1000.


Рисунок 6 Варианты тестирования

Вариант 3
Для проверки программной IP-АТС нам понадобится Asterisk + T1/E1 (PRI) Digital Card в разрыв потока E1 ставится анализатор потока E1. Дальше используются генераторы трафика StarTrinity SIP Tester или Sipp, которые осуществляют вызовы на Asterisk (Asterisk подымает трубку и заворачивает RTP). Сообщение протоколов анализируем с помощью Linkbit AnyTest AT1000.

Вариант 4
Для проверки программной IP-АТС нам понадобится Asterisk + T1/E1 (PRI) Digital Card. Дальше используются генераторы трафика StarTrinity SIP Tester или Sipp, которые осуществляют вызовы на Asterisk (Asterisk подымает трубку и заворачивает RTP). Сообщение протоколов анализируем с помощью программных возможностей Asterisk. Сообщение протоколов анализируем с помощью Linkbit AnyTest AT1000.


Рисунок 7 Варианты тестирования

У меня было несколько видов проверок первая я занимал 30 каналов и с определенным интервалом устанавливал вызовы, что бы отбившийся канал занимался новым и так по кругу, проще всего это сделать с помощью StarTrinity SIP Tester. Вторая направлял вал вызовов через поток и смотрел как будет реагировать программное обеспечение.

Подведение итогов
Подведем итоги, мы с вами разобрались как работает протокол EDSS-1, нашли способы проанализировать сообщения протокола и произвели нагрузочное тестирование программного обеспечения. Конечно, в данном посте нет описания сообщений и всех тонкостей работы протокола, но для этого есть ссылки с рекомендуемыми спецификациями и литературой.

LOADING.

Ссылки
1.ITU-T Recommendation Q.921 (I.451)
2.ITU-T Recommendation Q.931 (I.451)
3.Гольдштейн Б.С. Протоколы сети доступа. Том 2.
Подробнее..

Голосовая аналитика бесплатно. Что? Где? Когда?

22.12.2020 18:11:09 | Автор: admin
Большая часть продаж и поддержки все так же происходит по телефону, и во времена удаленки эта цифра только возрастает. Но как контролировать сотрудников колл-центра? Специально для этого и существует голосовая аналитика.
Как она работает, как пользоваться, и как попробовать бесплатно, мы расскажем ниже.




Что такое голосовая аналитика?


Голосовая аналитика комплексное решение анализа речи. Нейросети переводят разговоры из голоса в текст, затем текст анализируется по нескольким параметрам. В частности, инструмент умеет анализировать:

  • скорость разговора,
  • перебивание,
  • молчание,
  • искать ключевые слова,
  • выставлять сводную оценку каждому разговору.


Кому пригодится?


Тем у кого больше одного сотрудника, кто разговаривает по телефону (продажи/поддержка/опросы что угодно).
Слушать все разговоры невозможно. Благодаря автоматическому скорингу, все плохие(или наоборот) разговоры вы сразу же можете прочитать или прослушать в интерфейсе личного кабинета.

Словари и ключевые слова


Инструмент речевой аналитики Zadarma прошел этап альфа-тестирования и мы можем сказать, что чаще всего клиенты используют словари и ключевые слова. В разговоре были употреблены слова из дефолтного словаря (например, использование слов-паразитов оператором), либо из созданного словаря. Руководитель узнает об этом, сможет прочитать расшифрованный текст или прослушать разговор.

Чтобы не тратить время, можно анализировать употребление ключевых слов только на одном канале (у клиента либо сотрудника). Например, если ищете слова-паразиты в разговоре, то не важно, употребляет ли их клиент. Но если менеджер или оператор часто использует ну, как бы, проще говоря, то это лишний повод задуматься. Вот некоторые примеры словарей или ключевых слов:

Слова оператора
Неуверенная работа оператора не знаю, не уверен, не могу помочь
Скрипты покупка совершена, ваш заказ принят в обработку, спасибо за покупку

Слова клиента
Плохое качество связи не слышно, мямлите, внятнее, громче
Недовольство клиента себе позволяете, разговаривайте корректно, хамство, не хамите
Повторное обращение я уже звонил, звонил с другого номера, только что говорил, только что разговаривал
Нецензурная лексика обойдемся без примеров

Слова оператора и клиента
Упоминание конкурентов Кола, пепси, спрайт, миринда, вятский квас
Ошибки, баги сбой, не работает, техническая ошибка, неполадки, зависло

Также система может строить отчеты по дополнительным параметрам: молчание, перебивание (в % эквиваленте), скорость речи, соотношение речи оператора и клиента.
Пример такого отчета:



Сколько стоит и как попробовать?


Сам инструмент речевой аналитики абсолютно бесплатный. Это не первый наш бесплатный инструмент (например бесплатная АТС, коллтрекинг, CRM, виджеты). Платить нужно только за минуты распознавания речи.
Инструмент умеет работать с 50+ языками, и стоимость зависит от языка.
Стоимость распознавания популярных языков, в том числе и русского 90 копеек за минуту разговора.



До 15 января 2021 года мы добавили подарочные минуты для трех тарифов:
  • Стандарт 100 минут бесплатного распознавания (действует только до 15 января)
  • Офис 500 минут бесплатного распознавания (после акции 100 минут)
  • Корпорация 1000 минут бесплатного распознавания (после акции 200 минут)


Для того, чтобы протестировать речевую аналитику:
  1. зарегистрируйтесь в сервисе
  2. подключите бесплатную АТС и виртуальный номер
  3. активируйте распознавание всех разговоров на одном или нескольких внутренних номерах АТС.
  4. далее создайте параметры отчета разговора в разделе Распознавание речи.


P.S. Все должно совершенствоваться. Так как мы предложили голосовую аналитику лишь несколько дней назад, то активно наращиваем ее функционал. Все пожелания по развитию голосовой аналитики с радостью ждем в комментариях.
Подробнее..

Переезд производственной компании с железок на виртуальную АТС

14.09.2020 18:23:30 | Автор: admin

Статья про опыт интеграции ВАТС для производственной компании. Клиент производитель крепежа и строительного оборудования со складами в Москве, Петербурге, Сургуте и Рязани.

Ранее мы уже писали, как разрабатывали скрипт сопоставления номенклатуры (SKU) для этого клиента (ссылка на предыдущую статью с vc.ru). В этой статье расскажем про процесс переноса телефонии и про то, с какими сложностями мы столкнулись.

Почему решили перейти на ВАТС

Использовать аналоговые линии телефонии нормально, в некоторых случаях даже удобно. Но задача нашего клиента объединить звонки всех филиалов в единой системе и фиксировать все в CRM. Это проще и дешевле сделать через виртуальную телефонию, нежели покупать дорогое оборудование и синхронизировать железо.

Затраты на оборудование и его обслуживание

Мы посмотрели на исходную телефонию филиалов и поняли, что везде стоит разное оборудование: в Рязани CISCO, в Москве и Петербурге Asterisk, в Сургуте Panasonic. На одно только обслуживание этого парка уходило по 90к в месяц.

Чтобы собрать воедино аналоговую телефонию для четырех регионов, нужно поставить одинаковое оборудование в каждом из них, иначе синхронизация будет дорогой. Тем более для разного оборудования нужны разные специалисты. Например, у Panasoniс свои специалисты, у CISCO другие.

Распределение звонков по ответственным менеджерам

В аналоговой системе трубки привязываются к конкретному номеру и распределяются между менеджерами. Представим ситуацию, когда клиент повторно звонит в компанию и ему нужно попасть на менеджера, который с ним работал.

Клиент звонит на главный номер и просит оператора перевести его на нужного менеджера, или сам вводит внутренний (добавочный) номер менеджера. Многовато действий для клиента, не правда ли?

Виртуальную АТС можно интегрировать с CRM-системой. Тогда при повторном входящем звонке клиент сразу будет попадать на менеджера, который с ним работал. Звонки из стационарной телефонии тоже можно завести в CRM-систему, но это намного сложнее и дороже в интеграции, особенно, если у вас несколько офисов.

Звонок на 8 800 или на региональный номер

В 8 800 есть сценарий распределения через IVR. Это интерактивное голосовое меню, в котором пользователь выбирает следующий шаг.

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

Процесс перехода на ВАТС

1 определяем сценарий

Важно понимать, как должен идти звонок, от этого зависит процент удержания входящих обращений. Пример сценария:

пример сценария одного из наших проектовпример сценария одного из наших проектов

2 выбираем ВАТС

Выбираем удобный интерфейс у АТС. Смотрим тарифы и стоимости минуты разговора, а также стоимость абонентской платы за пользователей.

У кого-то дешевле междугородние звонки, у кого-то наоборот. Важно понять, какие направления у вас чаще встречаются. Самый простой лайфхак смотреть на стоимость звонка на мобильный, она всегда выше всех остальных (доходы по минимуму, расходы по максимуму).

Также стоит оценить объем трафика. Большой объем отличная причина поторговаться с провайдером.

3 определяем, нужно ли сохранить номера при переходе

Есть цифровые и аналоговые номера. У цифровых есть SIP данные для работы в цифровых каналах связи. У аналоговых номеров таких данных нет они работают через маршрутизаторы.

Если нужно сохранить номер при переходе, то запрашивайте SIP данные аккаунта и затем подключайте этот номер как внешний к вашей АТС.

В 2020 уже никого не удивишь красивым номером и ни к чему за него переплачивать. Тем более можно просто сделать переадресацию со старого номера, а звонить уже с нового.

4 выбираем и подключаем оборудование

С оборудованием есть несколько вариантов:

  1. Софтфоны. Это приложение на телефоне или ПК, через которое можно звонить. Удобно то, что это мобильно. Но с софтфоном вы сильно зависите от качества интернета.

  2. Расширения для браузера. Минимум затрат, но нужна привязка к рабочему месту и гарнитура.

  3. IP-телефон отдельный класс оборудования (отдельная трубка). Плюсы стабильно и долговечно. Минус не мобильно.

  4. FMC Fixed Mobile Convergence. Менеджеры часто звонят с мобильных. Но, чтобы фиксировать звонки, нужно ставить софтфоны и надеяться на интернет. С недавнего времени есть вариант писать звонки напрямую с симкарт через FMC. Это намного удобнее и стабильнее в плане работы. Даже не нужно вводить префиксы.

5 интегрируем АТС с CRM

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

После этого, через API UIS, входящий звонок коммутируется с телефоном менеджера. В CRM всплывет карточка с информацией по звонящему, в которую можно заносить информацию.

По итогам разговора создается контакт и сделка, в них подтягивается ссылка на запись с возможностью прослушки. Менеджеру автоматически ставится задача с контрольной отсечкой по клиенту.

Сложности при внедрении

Разделение личного кабинета внутри АТС

У компании настроена интеграция Creatio CRM с ВАТС. Но через одну интеграцию подключено сразу 4 личных кабинета, чтобы разводить расходы по разным регионам. Не важно, куда звонит клиент он все равно попадает к нам в CRM.

Также, для менеджеров каждого региона выделены отдельные номера. Чтобы менеджеры могли переводить звонок между разными регионами = разными кабинетами.

1 Москва. 2 Санкт-Петербург. 3 Рязань. 4 Сургут

Было бы проще, если бы все номера регионов хранились в одном личном кабинете. Но клиенту нужно было разводить финансовые потоки, поэтому сделали так.

Переадресация входящих

Из-за переадресации менеджер не видит номер клиента и ему нужно его переспрашивать. Минус невозможно привязать отдельные номера клиентовпод определенного менеджера, так как работает переадресация, и будет отображаться номер переадресации.

У UIS в операции переадресации можно настроить сценарий и выбрать номер, который будет отображаться менеджеру при входящем звонке.

При большом штате сложно настроить оборудование

У нас было 50 менеджеров и настраивать оборудование каждому сложно и долго. Поэтому мы разработали инструкцию и разместили ее на портале клиента. Менеджер делает все сам, а нам как админам остается лишь передать ему логин и пароль для доступа к ВАТС.

ВАТС не всегда дешевле железа

Когда подключают железо платят сразу и много. Самая простая станция стоит от 25к (базовый блок Panasonic на 24 абонента). Если сравнивать в перспективе железо вполне может окупиться. При условии, что не нужно будет часто расширять его парк.

Сложности с 8 800

Давно-давно у ноунейм компании купили основной номер, которым, как выяснилось, эта компания напрямую не владеет. Поэтому мы не могли получить данные по SIP транку.Чтобы это обойти мы настроили переадресацию с 8 800 на городской региональный номер.

Звонят на 8 800 идет приветствие сценарий IVR(голосовое приветствие с возможностью выбора региона) выбирают регион и звонок переадресуется на него. Если ничего не выбрано попадают на дежурного менеджера.

Но при такой схеме переадресации не всегда срабатывает донабор с выбором региона. Из-за этого терялись вызовы, клиенты не могли дозвониться и звонки терялись.

В итоге устали бороться с оператором и приобрели другой номер 8 800 у другого оператора, которой может дать данные SIP аккаунта номера.Теперь переадресация работает без сбоев. Номер заведен в ВАТС как внешний номер, и все работает корректно.

Внешний номер в ВАТС означает, что он обслуживается у одного оператора. Но его все равно можно привязать к другому.

Например, у вас номер Ростелекома, но вы не хотите разговаривать по их тарифам. Тогда вы берете данные SIP аккаунта и прописываете их в той АТС, с которой вы хотите работать. В итоге все входящие идут через нужную вам телефонию, и вы можете выбрать, как будут тарифицироваться звонки: по ценам старого или нового оператора.

Цифры

Мы проанализировали разницу в расходах до и после перехода на виртуальную АТС. Вот что получилось:

Город, услуга

Аналог

ВАТС

Итог

Петербург тарифное обслуживание

490 руб + 2,5 руб/мин

1 390 руб за 1000 минут, далее 0,5 руб/мин

Учитывая, что в среднем трафик был от 500 минут экономия видна сразу.

Москва стоимость одного из номеров

60 000 рублей в месяц

0 рублей в месяц

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

Все регионы маршрутизация

2 500 рублей в месяц

0 рублей в месяц

В виртуальной АТС услуга стала бесплатной

Рязань обслуживание железа

5 500 рублей в месяц

0 рублей в месяц

В виртуальной АТС услуги стали бесплатными

Также мы посчитали итоговую сумму затрат на внедрение и последующее обслуживание. Расчет на 130 пользователей и 5 офисов.

Стоимость настройки (разовая)

Абонентская плата в месяц

Стоимость обслуживания в месяц

Аналог

200,000

90,000

35,000

ВАТС

170,000

45,000

0

Дельта

30,000

45,000

35,000

Абонентская плата за аналоговую линию в 90к без учета дорогого номера за 60к. Стоимость обслуживания ВАТС 0 рублей, так как систему обслуживают штатные специалисты компании клиента.

Если у вас есть вопросы по телефонии пишите нам в комментарии к статье или в Фейсбук.


Интегратор LAND PRO. Телефония UIS. Редактор Фёдор Анисимов.

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru