При разработке мобильных приложений на платформе 1С часто возникает задача воспроизвести несколько звуковых сигналов или фраз подряд (например, озвучить число или статус документа). Если просто написать несколько вызовов метода воспроизведения подряд, все звуки начнут звучать одновременно, создавая какофонию. Попытки использовать циклы с паузой («слипы») приводят к зависанию интерфейса приложения.
Разберем детально, почему так происходит, и рассмотрим три способа решения этой задачи: от простого к архитектурно правильному.
Метод СредстваМультимедиа.ВоспроизвестиАудио в мобильной платформе работает асинхронно. Это означает, что когда платформа встречает эту строку кода, она отправляет команду операционной системе (Android или iOS) «начать проигрывание» и сразу же переходит к следующей строке кода, не дожидаясь окончания звука.
Если мы напишем такой код:
// Неправильный подход
СредстваМультимедиа.ВоспроизвестиАудио(Звук1);
СредстваМультимедиа.ВоспроизвестиАудио(Звук2);
СредстваМультимедиа.ВоспроизвестиАудио(Звук3);
Все три команды уйдут в систему практически мгновенно, и телефон начнет играть их одновременно. Использование циклов для задержки (паузы) на мобильном устройстве недопустимо, так как код 1С выполняется в основном потоке интерфейса. Любая искусственная пауза «заморозит» экран и может привести к ошибке «Приложение не отвечает».
Наиболее корректный способ управления очередью звуков — использование механизма обратных вызовов (callback). Метод ВоспроизвестиАудио имеет параметр ОбработчикОстановкиВоспроизведения.
Мы можем создать цепочку (рекурсию): запускаем первый звук и передаем системе инструкцию: «когда этот звук закончится, вызови процедуру, которая запустит следующий».
Рассмотрим пример реализации через рекурсивный вызов:
&НаКлиенте
Процедура ПроигратьПлейлист(СписокЗвуков, Индекс = 0)
// Если список закончился, выходим
Если Индекс > СписокЗвуков.Количество() - 1 Тогда
Возврат;
КонецЕсли;
ТекущийЗвук = СписокЗвуков[Индекс];
// Создаем оповещение, которое сработает ПОСЛЕ окончания звука
// Передаем тот же метод, но увеличиваем индекс на 1
ДополнительныеПараметры = Новый Структура;
ДополнительныеПараметры.Вставить("СписокЗвуков", СписокЗвуков);
ДополнительныеПараметры.Вставить("СледующийИндекс", Индекс + 1);
Оповещение = Новый ОписаниеОповещения("ОбработчикОкончанияЗвука", ЭтотОбъект, ДополнительныеПараметры);
// Запускаем звук и передаем оповещение третьим параметром
СредстваМультимедиа.ВоспроизвестиАудио(ТекущийЗвук, 0, Оповещение);
КонецПроцедуры
&НаКлиенте
Процедура ОбработчикОкончанияЗвука(ДополнительныеПараметры) Экспорт
// Получаем параметры и запускаем следующий трек
Список = ДополнительныеПараметры.СписокЗвуков;
СледИндекс = ДополнительныеПараметры.СледующийИндекс;
ПроигратьПлейлист(Список, СледИндекс);
КонецПроцедуры
Преимущества: Гарантирует отсутствие пауз и наложений, не блокирует интерфейс.
Если по каким-то причинам использование ОписаниеОповещения невозможно, можно воспользоваться методом ПодключитьОбработчикОжидания. Логика следующая: мы знаем длительность звука, запускаем его и взводим «будильник», который через нужное количество секунд запустит следующий звук.
Этот способ упомянут в теме как рабочий, но он менее надежен: если устройство «подвиснет» или длительность файла определена неверно, звуки могут наложиться или возникнет слишком длинная пауза.
&НаКлиенте
Процедура ЗапуститьОчередь()
// Запускаем первый звук
СредстваМультимедиа.ВоспроизвестиАудио(Звук1);
// Зная, что звук длится 2 секунды, планируем следующий через 2.1 сек
ПодключитьОбработчикОжидания("ЗапуститьВторойЗвук", 2.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура ЗапуститьВторойЗвук()
СредстваМультимедиа.ВоспроизвестиАудио(Звук2);
КонецПроцедуры
Если последовательность звуков всегда одинаковая (например, фраза приветствия), самым надежным и простым способом будет объединение их в один аудиофайл с помощью любого аудиоредактора. В этом случае коду 1С нужно будет вызвать команду воспроизведения всего один раз.
ПолучитьИзВременногоХранилища) каждый раз перед воспроизведением. Это вызывает задержки, зависящие от скорости интернета. Лучше кэшировать файлы на устройстве локально.РазрешитьФоновое (четвертый параметр метода ВоспроизвестиАудио), установив его в Истина.СредстваМультимедиа.СинтезРечи (TTS). Системный синтезатор речи на мобильных ОС обычно сам умеет выстраивать очередь фраз, что избавит вас от написания сложного кода.