Асылхан Райсханов, «Как мы делали аудиосообщения»

Похожие видео

Текстовая версия

Так всем привет меня зовут анна и сегодня мы поговорим о том как мы делали голосовые сообщения. И давай сначала ответим на пару вопросов поднимите?

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

Что далеко не все кто здесь присутствует делал: Или собирается делать голосовые сообщения но зачем тогда мы вообще собрались.

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

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

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

И и отправиться психику и помимо этих требований нам сказали сделать как в известных мессенджерах. Например telegram вот сам и вконтакте дизайн голосовых сообщений ну что ж казалось бы все есть дизайн. Есть какие-то требования теперь можно начинать ходить на самом деле нет как я сказал это распространенная ошибка который говорит.

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

Что так и первое что мы делаем.

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

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

Для начала мы диком позировали сдачу чтобы у нас были маленькие логические блоки которые можно делать отдельно и тестировать?

Тоже отдельно в общей сложности вышло около 14 15 подзадач. Но в принципе можно рассмотреть все эти по задаче следующим образом 1 часть это запись. Вторая часть это прослушивание если сделать эти две части то весь функционал.

Будет работать и что касается записей чтобы работала эта часть нам нужно было сверстать запись зачем записывать? Сама аудио и отправлять сообщение на сервер давайте начнем с верстки у записи.

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

Отправкой и перед нами встал вопрос как же это сверстать продумали решение первое решение? Которое пришло к нам голову это закинуть все в одну юбку но тут есть пара:

Рисков первый из них это то что юшка могла стать очень. Большой из за того что там появилось:

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

Говна код другое решение которое мы придумали. Это сверстать все по отдельности чтобы мы сами не путались во время разработки если! Когда-нибудь потом надо будет что-то доделать было самим же проще и так теперь у нас есть какое-то решение.

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

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

И связали их мы путем добавления как child контроллер что же теперь мы внутри factory. Ли код и готовы добавлять новый интерфейс новый элемент интерфейса в вёрстку и как я уже говорил мы решили создать все по отдельности: Его что у нас получилось отдельные viewcontroller и для каждого состояния и у нас есть четыре контроллера который никак.

Не связаны и надо было как-то менять состояние на этом этапе еще ничего не отображается на экране и надо было как-то это сделать для этого. Мы использовали отдельный viewcontroller который мы добавили так же как с после рефакторинга.

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

Добавляем экран записи затем если пользователь и удерживая кнопку меньше чем одну секунду удаляем этот экран и добавляем следующий то есть состояние? С подсказкой том что нужно удерживать кнопку чтобы записывать окей казалось бы все верстка готова!

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

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

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

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

То фиксить в итоге мы пришли к такому решению добавили опции того что они анимацию надо повторять и авто реверсировать то есть значение меняется: От старого к новому и обратно 5 посмотрим что у нас получилось. На этом все теперь у нас есть верстка но больше:

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

Чем лезть в 100 cover flow и копируйте тут костыли мы не стали сильно закапываться в документацию читайте целыми днями и ночами. Мы изучили достаточно чтобы написать рабочий код который что-то записывает и вот на чем мы остановились.

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

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

И прослушивание потому что нам больше всего подходит так мы будем записывать. Голосовые сообщения и прослушивать их для режима нам тут особо?

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

Много и в итоге у нас получился такой код мы указываем:

Категорию запись и прослушивание и указываем режим по умолчанию следующее! Что нам нужно это получить доступ микрофона как и с другими вещами волос например. Доступ местоположению какой галереи и так далее делается это опять-таки через аудио сессию и этот метод возвращает бульон который?

Определяет дал нам пользователь разрешение на микрофон или не дал если он разрешение не.

Дал то можно в следующий раз к нам попробовать записать. Аудио показать alert и попросить его включить доступ в настройках. Вручную последний этап который нам нужно чтобы уметь записывать.

Аудио это создание рекордер а для этого нам нужно две вещи первая это и url к файлу. Который будет в который будет сохраняться audio для этого мы использовали файл-менеджер добавили название файла и формат и вторая вещь которую нужно: Это настройки их больше чем настроек для аудио сессий и остановились мы на следующих первый это формат который мы заранее обговорили?

С бы киндерами который будет подходить и нам и андроиде рам и сайтом следующее это рейд мы использовали.

Дефолты который используется для аудио cd audio следующее это количество каналов так как в ios:

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

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

Был готов к тому чтобы записывать без этого настройки применяться только тогда когда мы начнем записывать? Это может привести каким-то лагом и отставанием теперь мы можем записывать!

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

Опять-таки мы указываем content type и выполняем обычный запрос который мы используем для отправки! Сообщений теперь вся запись готово у нас есть запись верстка и отправка на сервер отлично идем дальше 1 часть закончили теперь. Предстоит сделать прослушивание чтобы работала прослушивание нам опять опять таки надо сделать верстку затем скачивать.

Файл который мы ранее отправляли и воспроизводить аудио давайте снова начнем с верстки казалось.

Бы тут верстка попроще но на самом деле тут тоже много состояние между которыми надо переходить их тут. 4 и мы начали думать где я держать.

Логику первый вариант был держать во вьюшки но опять-таки код мог стать большим и мы бы простой плакали от того какой нас код написан другой вариант?

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

Каких-то нескольких свойств и это подходит нам потому что меньше боли и меньше путаницы чтобы! Меняет состояние мы завели и нумератор с этими состояниями и использовали паттерн.

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

На кнопку вызывается функция вьюшки которая обращается к виде модели.

Чтобы она поменяла состоянии и это в модель просто берет следующее.

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

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

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

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

Код так то есть каждую секунду слайдер двигается на одну секунду! И было 2 бага на коротких сообщениях сложно двигать слайдер то есть сложно было поймать.

Его из анимации и вторых бак то что на некоторых сообщениях:

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

Давайте сперва посмотрим как у нас устроен чат чат у нас является отдельным проектам которые используются. В нескольких проектах как под и чтобы связаться с api он проходит через проект в котором используется но так как backend! Прислал нам готовый url для скачивания файла мы решили не связывать код скачивания.

С проектом и оставить все внутри что-то чтобы оставить и внутри chateau мы использовали являлся task это простой но одновременно мощный. Механизм который позволяет выполнять сетевые запросы и при этом не подключать всякие библиотеки.

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

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

Другая проблема заключалась она в том что каждый раз когда мы открываем кран диалога все аудиофайлы грузится заново android с этим было больше проблем потому что android. Выделяет какой-то определенный объем памяти для использования приложения под кэш им пришлось с этим помучиться немного.

В итоге они сделали рука ширине это метод каширование когда самый давно.

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

Хранить данные мы использовали файл-менеджер для записей когда загружаем!

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

И после этого мы реализовали эту логику то есть мы проходимся по всем файлам и удаляем. Их из файл-менеджер какие мы загрузили данные.

У нас есть какая-то дата но нам из этого нужно сделать воспроизведение. Как это сделать тут нам подходит аудио плеер который.

Как раз таки можно инициализировать сданных его также?

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

Этот плеер мы использовали и в своем объекте player а его уже использовали в объем модели. Давайте вспомним как мы использовали модель и тут есть обращение к плееру чтобы начать воспроизведение. Или поставить его на паузу и эта логика используется в двух от выражениях не только в аудиосообщении но и в состоянии когда мы можем:

Прослушать свое голосовое сообщение в этом нам view model. Кассу сильно помогла потому что не пришлось дублировать логику.

В двух разных фишках и кот оказался:

Проще окей мы сделали воспроизведение но неожиданно.

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

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

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

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

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

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

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

Отслеживать изменение датчика приближения затем подписаться на уведомление через эти fashion center о том что либо датчик закрыли либо открыли и когда. Мы получаем уведомление о том что значение поменялось мы можем на него реагировать если значение фолз значит телефон.

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

От уха обратно включали его в итоге вышло. Как-то так теперь когда у нас готово прослушивания мы отдали. Его на тестирование и у нас появилась.

Куча багов например аудио продолжалось воспроизводиться когда вы блокировали телефон или когда вы включали музыку с другого приложения например?

Или когда просто закрывали экран звук продолжал выходить для этого мы завели и нумератор с названиями уведомлений на который подписываемся каждый раз когда воспроизводим аудио!

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

Прослушивание тоже давайте посмотрим живую как это выглядит давайте попробуем отправить! Кого-нибудь голосовое сообщение брат наградой тачку подешевле давай договоримся окей весь.

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

Варианты решения подбирать это подбирать правильное решение. И более подходящее и планировать решение заранее а также. Думать а также декомпозировать задач на более мелкие чтобы проще было самим работать и также вашим!

Коллегам чтобы было проще code review & telli тестировать все это нужно для того чтобы приносить. Пользователям больше ценностей за меньшее время всем спасибо.

Дополнительные материалы

Поделиться или сохранить к себе:
Твой успех