Обзор: фоновое аудио (приложения Магазина Windows Phone) (HTML)
[ Эта статья адресована разработчикам приложений среды выполнения Windows для Windows 8.x и Windows Phone 8.x. В случае разработки приложений для Windows 10 см. раздел последняя документация]
Вы можете писать для Windows Phone 8.1 приложения, которые воспроизводят звук в фоновом режиме. Это означает, что даже после того, как пользователь выйдет из вашего приложения, нажав кнопку Назад или Пуск на устройстве, ваше приложение продолжит воспроизводить аудио. В этой статье обсуждаются компоненты приложения фонового аудио и их совместная работа.
Сценарии фонового воспроизведения аудио включают следующие элементы.
- Долговременные плей-листы Пользователь кратковременно вызывает приложение переднего плана, чтобы выбрать и запустить плей-лист; после этого пользователь ожидает, что плей-лист продолжит воспроизведение в фоновом режиме.
- Использование диспетчера задач Пользователь кратковременно вызывает приложение переднего плана, чтобы запустить воспроизведение аудио, затем с помощью диспетчера задач переключается на другое открытое приложение. Пользователь ожидает, что воспроизведение аудио продолжится в фоновом режиме.
Совет Вы можете скачать пример background audio for Windows Phone 8.1, в котором реализован код, рассматриваемый в этом обзоре.
Архитектура фонового аудио
Приложение фонового аудио использует фоновые агенты. Однако воспроизведение аудио в фоновом режиме в Windows Phone 8.1 отличается от способа воспроизведения фонового аудио в Windows 8. Модель отличается также от агентов фонового аудио, которые использовались в более ранних версиях Windows Phone.
Важно
Приложения с фоновым аудио можно писать на JavaScript. Однако Windows Phone 8.1 не разрешает выполнять код JavaScript в фоновом процессе. Это значит, что приложение переднего плана и пользовательский интерфейс можно написать на JavaScript, но фоновая задача должна быть написана на C# или C++. В примере фонового аудио для Windows Phone 8.1 показано приложение JavaScript, поддерживающее фоновое аудио с помощью фонового агента на C#.
Пространство имен Windows.Media.Playback содержит универсальные API аудио, его можно использовать для воспроизведения музыки даже на переднем плане, однако их основная цель — воспроизведение аудио в фоновом режиме. При использовании этого API используется единый глобальный MediaPlayer, с помощью которого осуществляется все воспроизведение. Приложение фонового аудио отправляет команды проигрывателю мультимедиа, чтобы задать текущую дорожку, начать воспроизведение, выполнить приостановку, перемотку вперед, перемотку назад и т. п. Для этого вы вызываете методы для класса MediaPlayer. Объект экземпляра проигрывателя мультимедиа, вызванный с помощью свойства BackgroundMediaPlayer.Current, обменивается данными с глобальным проигрывателем мультимедиа для управления воспроизведением аудио.
Создать новые экземпляры MediaPlayer невозможно.
Используйте класс SystemMediaTransportControls для изменения событий, которые используются универсальным регулятором громкости (UVC). UVC — это пользовательский интерфейс, отображаемый при нажатии пользователем приложения регулятора громкости на его устройстве. SystemMediaTransportControls используется для управления проигрывателем мультимедиа. Помимо запуска воспроизведения из приложения вы можете управлять воспроизведением аудио. Например, используйте SystemMediaTransportControls для отправки событий в IBackgroundTask в вашем приложении, и вы сможете реализовать логику плей-листов. Мы подробнее обсудим IBackgroundTask позже в этом разделе.
На следующей схеме представлен очень простой вид разработанной системы. Приложение, выполняющее фоновое воспроизведение, состоит из двух процессов. Первый процесс — это основное приложение, содержащее пользовательский интерфейс, которое выполняется на переднем плане. Второй процесс — это задача фонового воспроизведения, содержащая механизм воспроизведения аудио, а также (в необязательном порядке) некоторую логику приложения. Процесс переднего плана приостанавливается или прекращается операционной системой согласно ее потребностям в ресурсах. Фоновый процесс продолжает выполняться.
В то время как воспроизведение аудио происходит в фоновом процессе, процесс переднего плана имеет доступ ко всей информации через прокси-объекты. Процесс переднего плана может управлять свойствами экземпляра MediaPlayer в фоновом процессе. Приложение переднего плана может получать уведомление о событиях, связанных с мультимедиа — таких как MediaOpened, MediaEnded и MediaFailed. Когда прекращается процесс переднего плана или приостанавливается приложение, мультимедиа продолжает проигрываться.
Системные элементы управления передачей мультимедиа
SystemMediaTransportControls — это новый набор API, введенный в Windows 8.1. В Windows Phone 8.1 также реализован этот класс, но в Windows Phone существует один глобальный регулятор громкости, поэтому взаимодействовать с ним может единовременно только один процесс. В контексте API MediaPlayer особенно важно определить экземпляр и все его дескрипторы в фоновом процессе. Это обеспечит соединение с правильным процессом в случае, когда прекращен процесс переднего плана.
Отправка сообщений между задачами
Иногда возникает необходимость связи между двумя процессами приложения фонового аудио. Например, может потребоваться, чтобы фоновая задача уведомляла задачу переднего плана, что начинается проигрывание новой дорожки, и отправляла в задачу переднего плана название новой песни для отображения на экране. Простой механизм связи позволяет вызывать события как в процессе переднего плана, так и в фоновом процессе. Каждый из методов SendMessageToForeground и SendMessageToBackground вызывает события в соответствующей задаче. Данные могут передаваться как аргумент в обработчик событий в принимающей задаче. Передавайте данные с помощью нового класса с именем ValueSet. Этот класс является словарем, содержащим строку в качестве ключа и другие типы значений в качестве значений. Вы можете передавать простые типы значений, такие как int, string, bool и т. д.
Жизненный цикл фоновой задачи
Жизненный цикл фоновой задачи тесно связан с возможностью приложения воспроизводить музыку. Например, когда пользователь приостанавливает воспроизведение аудио, система может завершить или отменить ваше приложение в зависимости от обстоятельств.
Фоновые задачи запускаются, когда приложение в первый раз получает доступ к BackgroundMediaPlayer.Current в коде вашего приложения переднего плана или когда вы регистрируете обработчик события MessageReceivedFromBackground, в зависимости от того, что происходит раньше. Чтобы убедиться, что каналы коммуникации установлены при вызове метода IBackgroundTask.Run, необходимо зарегистрировать событие MessageReceivedFromBackground, перед тем как в первый раз осуществлять доступ к свойству BackgroundMediaPlayer.Current. Прежде чем запустить любое воспроизведение аудио, ваше приложение должно дождаться начала выполнения фоновой задачи. При этом вы получите возможность подписываться на события мультимедиа.
Чтобы поддерживать активность фоновой задачи, ваше приложение должно получать BackgroundTaskDeferral в методе Run и вызывать BackgroundTaskDeferral.Complete, когда экземпляр задачи получает события Canceled или Completed. Не используйте ждущий цикл в методе Run, так как это ведет к потреблению ресурсов и может привести к завершению работы фоновой задачи вашего приложения.
Ваша фоновая задача получает событие Completed, когда завершается метод Run и не запрашивается отсрочка выполнения. В некоторых случаях, когда ваше приложение получает событие Canceled, за ним может следовать событие Completed.
Фоновая задача может быть отменена в следующих ситуациях.
- Запускается новое приложение с возможностями воспроизведения аудио.
- Фоновая задача была запущена, но проигрывание музыки не началось; в этом случае фоновая задача приостанавливается.
- Через некоторое время после запуска фоновой задачи приостанавливается воспроизведение, и фоновая задача останавливается. Воспроизведение может быть остановлено пользователем или с помощью других способов прерывания мультимедиа — например, с помощью поступивших телефонных вызовов или вызовов по протоколу VoIP. Если телефонный разговор или вызов по протоколу VoIP завершается в течение пяти минут, ваше приложение получит уведомление Run с помощью кнопки SystemMediaTransportControlsButton.Play, указанной в SystemMediaTransportControlsButtonPressedEventArgs. Если нет, пользователю придется явным образом включить воспроизведение музыки с помощью UVC. UVC не теряет свое состояние. Однако при нажатии пользователем кнопки Воспроизведение фоновая задача запускается заново. После этого вы получаете вызов метода Run и уведомление SystemMediaTransportControlsButton.Play.
Фоновая задача может быть отменена без предупреждения в следующих ситуациях.
- Поступают вызовы VoIP и недостаточно памяти.
- Политика ресурсов нарушается.
- Имеют место аварийные отмена или завершение задачи.
Рекомендации по фоновому аудио
Конвейер мультимедиа по своей природе является асинхронным. Это означает, что запуск событий гарантирует только возникновение таких событий, но не их порядок. Например, когда ваше приложение получает аудиофайл из удаленного источника, приложение будет получать различные события изменения состояния, такие как Starting, Paused, Closed и т. д. Обработчики таких событий не обязательно будут вызываться каждый раз в одном и том же порядке. Вы не должны полагаться на значения CurrentState в обработчике CurrentStateChanged.
Событие MediaOpened является очень важным и играет несколько ролей. Если вы задали для AutoPlay значение false и задали источник для MediaPlayer, вы по-прежнему будете получать MediaOpened. Это указывает, что конвейер мультимедиа инициирован, и все готово к воспроизведению вашего мультимедиа. Когда вы зададите источник, воспроизведение мультимедиа начнется автоматически. Вам нет необходимости вызывать Play после задания источника. Еще одним очень полезным приемом является явное воспроизведение при готовности мультимедиа. Для этого можно задать для AutoPlay значение false и специально вызвать Play в вашем обработчике MediaOpened.
Вы можете указать для источника мультимедиа разные типы содержимого, вызывая SetUriSource, SetFileSource, SetMediaSource или SetStreamSource. MediaPlayer также имеет возможность воспроизводить защищенное содержимое. Помимо задания URI источника, система зависит от выполняющихся в памяти объектов или кода приложения. Кроме того, фоновые процессы не будут знать о процессах памяти в задаче переднего плана. Поэтому определяйте все объекты таким образом, чтобы их источники задавались только в фоновом процессе. Если ваше приложение будет пытаться задать источник, отличный от URI в процессе переднего плана, в системе будет возникать InvalidCastException.
BackgroundMediaPlayer.Shutdown закрывает конвейер мультимедиа и удаляет из памяти объект MediaPlayer. Попытка получить доступ по ссылке на BackgroundMediaPlayer.Current снова после вызова Shutdown приведет к ошибке. Shutdown рассчитан на то, что после отмены задачи приложение очищает конвейер мультимедиа.
Когда ваше приложение приостанавливается, не забывайте отменять подписку на события MediaPlayer, чтобы не было ненужной активности, которая потенциально может привести к завершению работы выполняемого процесса. Однако это не означает, что процесс переднего плана уйдет из переключателя задач, и у пользователя по-прежнему будет возможность вернуться в приложение. Если после возобновления работы вашего приложения ссылка на приостановленный MediaPlayer еще сохраняется, то при отмене задачи воспроизведения фонового аудио и завершении работы конвейера мультимедиа возникнет ошибка.