Заявка на обратный звонок
Мы свяжемся с вами и ответим на любые возникшие вопросы!
Нажимая на кнопку «Отправить» , я соглашаюсь с политикой конфиденциальности и условиями обработки персональных данных, а также даю согласие на получение информационных рассылок

создания голосового мессенжера для OC Android

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

Цель данной статьи- пройти весь процесс создания голосового мессенжера для OC Android.

1. Описание предметной области

1.1 Библиотека OpenSL ES

Opens SL ES, Open Sound Library for Embedded Systems (открытая звуковая библиотека для встраиваемых систем) — бесплатный, кроссплатформенный, аппаратно ускоренный, программный интерфейс для работы со звуком, созданный для встраиваемых систем – мобильных телефонов, планшетов, консолей и т.д. Предоставляет стандартизованный, высокопроизводительный доступ с низкими задержками к аудио устройствам этих систем. Написан на языке C. Имеет низкие требования к аппаратной платформе.


Основные возможности, предоставляемые библиотекой OpenSL ES:

- Воспроизведение и запись звука
- Эффект объёмного звучания (3D Audio)
- Дополнительные звуковые эффекты
- Использование аппаратных и готовых программных кодеков


Работа с OpenSL ES построена на создании объектов и использовании их интерфейсов. Объекты представляют из себя обычные структуры языка С, содержащие указатели на функции, которые получают указатель на саму структуру первым аргументом и прочие параметры.

В OpenSL ES существуют два основных типа структур:

Объект (SLObjectItf) – представляет собой абстрактный ресурс и позволяет получить объекты-интерфейсы для использования этого ресурса. Например, ресурс - аудио плеер с функциями воспроизведения, изменения громкости, перемотки и т.д

Объект-интерфейс (SLEngineItf, SLPlayItf, SLSeekItf и тд) – представляет собой набор функций, реализуемых определённым ресурсом.

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




1.2 Протоколы передачи данных

Протокол UDP

Протокол UDP (User Datagram Protocol - протокол пользовательских датаграмм) является одним из двух основных транспортных протоколов, расположенных непосредственно над сетевым уровнем модели OSI (Open Systems Interconnection). Протокол не обеспечивает надежную доставку данных и работает без установления соединения, что позволяет передавать данные с минимальной задержкой. UDP является оптимальным вариантом для приложений, не чувствительным к потерям некоторой части данных, например, для голосовых звонков или мультиплеерных игр, но ставящим требования получения информации в реальном времени.

На максимальную длину датаграммы накладываются некоторые ограничения, что следует учесть для приложений, использующих UDP. Большая длинна пакета может привести его к фрагментации и если конечный хост или промежуточный маршрутизатор не поддерживает фрагментированные IP пакеты, то они соответственно будут потеряны. Согласно RFC 791 минимальная длина IP пакета в 576 байт должна поддерживаться всеми устройствами сети. Тогда размер данных в UDP не должен превышать (минимальна длина IP пакета) – (заголовок IP) – (заголовок UDP) = 576 – 60 -8 =508 байт. С другой стороны, MTU (Maximum transmission unit) – максимальный размер блока данных одного пакета, который может быть передан без фрагментации, для Ethernet по умолчанию составляет 1500 байт. Тогда размер данных в UDP не должен превышать (MTU)-(заголовок IP)- (заголовок UDP) =1500 – 60 – 8 = 1432 байта.




Протокол TCP

Протокол TCP (Transmission Control Protocol ) наравне с UDP является протоколом транспортного уровня модели OSI. TCP обеспечивает установление соединений, осуществляет повторный запрос и отправку данных в случае потери, устраняет дублирование входящих пакетов и гарантирует этим целостность передаваемых данных.

Для голосового мессенджера TCP протокол менее предпочтителен, поскольку создаёт большую задержку при передачи данных. Также он не позволяет устанавливать прямые соединения между клиентами, если они оба находятся за NAT (эта проблема будет рассмотрена далее). Этот протокол может отлично себя показать при клиент-серверной архитектуре, в ней он будет отвечать за приём и передачу команд, когда UDP будет использован для отправки и приёма голосовых данных.



Механизм NAT

NAT, Network Address Translation (преобразование сетевых адресов) — это механизм, позволяющий преобразовывать IP-адреса передаваемых пакетов. NAT используется как многими интернет провайдерами, так и пользователями для решения проблемы нехватки реальных IP-адресов и обеспечения безопасности локальных сетей, подключенных к Интернету. IPv4 адрес, состоит из 4 байт, он может представлять всего 232 или 4 294 967 296 уникальных адресов, что для текущих размеров сети чрезвычайно мало. Для решения этой проблемы, в качестве временной меры, было предложено разделить всё адресное пространство на публичные и приватные диапазоны. К последним относятся 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16. NAT заменяет внутренний IP-адрес и порт, чаще всего находящиеся в приватном диапазоне, на публичный IP-адрес и порт при запросах во внешнюю сеть. При этом сохраняется таблица соответствия адресов и портов, чтобы при получении ответного пакета произвести обратное преобразование. Полноценным решением проблемы нехватки адресов является использование IPv6 с количеством адресов равным 2128 .


Методы трансляции адресов NAT:

Full-cone NAT – при отправке сообщения во внешнюю сеть, внутренний адрес iIP:iPort транслируется во внешний адрес eIP:ePort. Все сообщения с iIP:iPort отправляются через eIP:ePort. Любой внешний узел может отправлять пакеты iIP:iPort, посылая их на eIP:ePort. Адрес и порт источника в данном варианте значения не имеют.

Address-restricted-cone NAT - при отправке сообщения во внешнюю сеть, внутренний адрес iIP:iPort транслируется во внешний адрес eIP:ePort. Все сообщения с iIP:iPort отправляются через eIP:ePort. В отличии от Full-cone NAT, внешний узел sIP:AnyPort может посылать пакеты к iIP:iPort через eIP:ePort, только если до этого внутренний узел отправлял пакеты к sIP:AnyPort. В данном варианте проверяется IP адрес источника, порт значения не имеет.
Port-restricted-cone NAT – режим аналогичный Address-restricted-cone NAT, только помимо адреса источника проверяется и порт источника. То есть если iIP:iPort посылал через eIP:ePort узлу sIP:sPort пакеты, то только sIP:sPort может отправлять данные iIP:iPort.
Symmetric NAT - при отправке сообщения во внешнюю сеть, внутренний адрес iIP:iPort транслируется в уникальный внешний адрес eIP:ePort для каждого sIP:sPort. Только внешний узел sIP:sPort может посылать данные к iIP:iPort через eIP:ePort, причём если до этого iIP:iPort отправлял пакеты к sIP:sPort.
бакалавриат
Разработка интернет-приложений
Обход NAT

Механизм NAT создаёт проблемы для соединений типа p2p (peer-to-peer) –соединений, в которых узлы взаимодействую напрямую и одновременно играют роль клиента и сервера. Для голосового мессенджера p2p является лучшим вариантом, и есть три основных способа обхода NAT, для его использования.

Первый – это Port Forwarding или «Проброс портов», который настраивается вручную на маршрутизаторе, использующем NAT, с целью перенаправления трафика определённых портов с внешнего адреса маршрутизатора на указанный внутренний адрес в локальной сети. Данный вариант не подходит для использования, так как требует от пользователя дополнительных действий, и пользователь не всегда имеет доступ к настройкам маршрутизатора.

Второй вариант - UDP Hole Punching, использует особенности трансляции адресов NAT для установления соединения. Но не работает при Symmetric NAT. Суть метода заключается в определении своих внешних адресов IP:Port собеседниками и обмене ими через сторонний сервер. Тогда на полученный IP:Port отправляется пакет, создающий запись в таблице трансляции NAT, при этом отправитель может начать получать данные от собеседника в течении времени жизни этой записи.

Третий вариант – выделенный сервер. Сервер имеет публичный адрес, к нему напрямую подключаются клиенты. При запросе от клиентов, сервер начинает ретранслировать данные полученные от первого клиента, ко второму и данные от второго к первому.

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

1.5 Библиотека QT

Qt - кроссплатформенный фреймворк для разработки программного обеспечения на языке программирования C++. Программное обеспечение, написанное с применением этого фреймворка может работать в большинстве современных операционных систем, это достигается путём простой компиляции программы для каждой системы без изменения исходного кода. Включает в себя все основные классы, которые могут потребоваться при разработке прикладного программного обеспечения, начиная от элементов графического интерфейса и заканчивая классами для работы с сетью, базами данных, последовательными портами, XML файлами и т.д. Является полностью объектно-ориентированным, расширяемым и поддерживающим технику компонентного программирования.

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

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




1.6 Инструменты разработки под ОС Android

1.6.1 SDK и NDK

Android SDK (Software Development Kit) — универсальное средство разработки приложений для операционной системы Android на языке Java. Содержит огромное число библиотек для взаимодействия как с самой операционной системой, так и с разнообразной периферией устройства – от встроенной камеры, динамиков, WiFi и GSM модулей, до внешних устройств, подключённых по USB, Bluetooth и т.д. Помимо этого, наличие широких функциональных возможностей позволяет запускать тестирование и отладку исходных кодов, оценивать работу приложения в режиме совместимости с различными версиями ОС и наблюдать результат в реальном времени. Поддерживает большое количество устройств: мобильные телефоны, планшеты, умные часы, умные очки, телевизоры и даже автомобили.

Android NDK (Native Development Kit) – это набор инструментов, которые позволяют реализовать часть приложения для ОС Android (чаще всего в виде библиотеки), используя языки С/С++, что значительно добавляет производительности.

1.6.2 Механизм JNI

Java Native Interface (JNI) — стандартный механизм для запуска кода под управлением виртуальной машины Java (JVM), который написан на языках С/С++ или Ассемблере и скомпонован в виде динамических библиотек, позволяет не использовать статическое связывание. Это даёт возможность вызова функции С/С++ из программы на Java, и наоборот. В Java коде необходимые функции из библиотеки декларируются с использованием ключевого слова native. Сама же библиотека загружается посредством функции System.loadLibrary(). Для С/C++ кода функциям в названии добавляется определённая строка, включающая название пакета приложения.


2. Программная реализация

2.1 Серверная часть

Для установления соединения между клиентами используется промежуточный сервер, который пропускает через себя весь голосовой трафик. Соответственно его задача заключается в приёме данных от клиента 1 и отправке их клиенту 2, аналогично данные принимаются от клиента 2 и отправляются клиенту 1.

Данный алгоритм может быть расширен и для большего числа клиентов (групповой разговор). На рисунке 2.1 представлен алгоритм работы сервера. После подключения клиентов сервер ждёт получения команды начала разговора, как только команда приходит, сервер начинает ретрансляцию и данные от одного из клиентов он пересылает второму. При получении команды завершения сервер перестаёт транслировать данные и ожидает нового подключения клиентов.
Работа сервера основана на использовании класса QUdpSocket библиотеки Qt. На порте 36002 ожидаются сообщения размером в BUFSIZE (константа, устанавливающая размер блока передаваемых данных). При получении такого пакета сервер проверяет адрес источника и убеждается что сообщение пришло от одного из клиентов. После проверки оно пересылается второму клиенту, адрес которого, также, как и адрес первого, были сохранены при подключении.



2.1 Клиентская часть

Клиентская часть представляет собой приложение под ОС Android. Пользовательских интерфейс реализован в главном Activity (компонент приложения, который показывает пользователю интерфейс для взаимодействия) написанном на Java. Весь основной функционал реализован в библиотеке, написанной на C++, код из которой вызывается посредством JNI.

Запись и воспроизведение звука реализуются с помощью библиотеки OpenSL ES. Инициализация библиотеки происходит при запуске приложения. После нажатия кнопки «Вызов» происходит основная часть работы. Для записи звука используется два буфера работа с которыми ведется параллельно. В 1 буфер библиотека записывает звук, когда из второго данные отправляются на сервер. После того как первый буфер будет заполнен, библиотекой OpenSL вызывается зарегистрированный «callback», в нём ожидается завершение отправки данных на сервер и эти буферы меняются ролями. Теперь во второй буфер происходит запись звука, когда первый буфер, уже заполненный данными, отправляется на сервер. Воспроизведение звука происходит подобным образом, также используются два буфера. В один из них параллельно данные приходят с сервера, а из другого данные воспроизводятся. Как только библиотека заканчивает воспроизведение одного буфера вызывается «callback», в котором буферы меняется местами. При повторном нажатии на кнопку «Вызов», разговор завершается. Блок-схема алгоритма представлена на рис. 2.4
Работа с сетью в клиентской части ведётся через Socket API и реализована в классе UDPTransceiver. Как было сказано выше, параллельно ведётся отправка данных и приём от сервера. За время, пока библиотека записывает и воспроизводит данные из первых буферов, необходимо их соответственно отправить и получить во вторые. Это необходимо для непрерывного обмена и качественной голосовой связи. Такой метод называют двойной буферизацией. Размер буферов устанавливается константой, которая по сути определяет длительность записи и воспроизведения одного пакета данных.




3. Исследование

3.1 Качество связи в зависимости от размера буфера

Задача заключается в определении допустимых его размеров. Эксперимент был поставлен на двух мобильных телефонах, первый был подключён к сети через Wi‑Fi, второй через мобильную сеть c 4G.

При размере буфера менее 30 байт, часто возникали трески и разрывы в звуке, поскольку буфер не успевал заполняться и воспроизводиться библиотекой Open SL ES. При увеличении размера буфера вплоть до 700 байт, соединение было стабильно и никаких звуковых артефактов не наблюдалось, но при этом также увеличивалась задержка из-за чего приходилось ждать ответа некоторое время. Но даже с этой задержкой было вполне удобно вести разговор.

После достижения размера буфера в 730 байт, абонент с телефоном, подключённым к Wi-Fi переставал слышать собеседника, но при этом собеседнику отправлялся без потерь. Такая ситуация было до размера в 733 байта. Уже оба собеседника переставали слышать друг друга.

Оптимальный вариант – динамически меняющийся, в зависимости от стабильности соединения, размер буфер от 50 до 200 байт.




Заключение

В данной статье была реализована базовая часть голосового мессенджера для OC Android, заложены основы и определены пути дальнейшего развития приложения – такие как: добавление чата и прочих функции с использованием сервера; прямое соединение клиентов по протоколу UDP с применением алгоритма UDP hole punching; добавление сжатия звука, для уменьшения трафика; добавление шифрования.

В процессе реализации были использованы различные библиотеки и технологии разработки программного обеспечения: библиотеки Qt, OpenSL ES; система контроля версий Git.

Так же были исследованы некоторые особенности прохождения UDP пакетов и определено оптимальное значение их размера для голосового трафика.
бакалавриат
Разработка интернет-приложений
Нажимая на кнопку «Отправить» , я соглашаюсь с политикой конфиденциальности и условиями обработки персональных данных, а также даю согласие на получение информационных рассылок
Записаться на ближайший онлайн день открытых дверей
в Институте Информационных Технологий
Заявка на обратный звонок
Мы свяжемся с вами и ответим на любые возникшие вопросы!
Нажимая на кнопку «Отправить» , я соглашаюсь с политикой конфиденциальности и условиями обработки персональных данных, а также даю согласие на получение информационных рассылок