概述:后台音频(Windows Phone 应用商店应用)(HTML)
[ 本文适用于编写 Windows 运行时应用的 Windows 8.x 和 Windows Phone 8.x 开发人员。如果你要针对 Windows 10 进行开发,请参阅 最新文档 ]
你可以为 Windows Phone 8.1 编写可在后台播放音频的应用。这意味着即使用户通过按设备上的“后退”按钮或“开始”****按钮离开应用,你的应用仍然可以继续播放音频。本文讨论了后台音频应用组件以及同时使用这些组件的方式。
后台音频播放的方案包括:
- 长期运行的播放列表用户可以简单地弹出前台应用以选择并启动一个播放列表,在此之后,用户将期望该播放列表在后台保持持续运行。
- 使用任务切换器用户可以简单地打开前台应用以开始播放音频,然后使用任务切换切换到另一个打开的应用。用户将期望该音频在后台继续保持运行。
提示 你可以下载 Windows Phone 8.1 的后台音频示例的代码,该示例可实现本概述中讨论的代码。
后台音频体系结构
后台音频应用使用后台代理。但是,在 Windows Phone 8.1 中播放后台音频的方式与在 Windows 8 中播放后台音频的方式不同。该模型也不同于在较早版本的 Windows Phone 中使用的后台音频代理。
要点
你可以使用 JavaScript 编写后台音频应用程序。但是,Windows Phone 8.1 不允许 JavaScript 在后台进程中运行。这意味着,可以使用 JavaScript 编写你的前台应用和 UI,但是必须使用 C# 或 C++ 编写你的后台任务。Windows Phone 8.1 的后台音频示例提供了一个 JavaScript 应用的示例,该应用通过使用 C# 后台代理支持后台音频。
Windows.Media.Playback 命名空间引入通用音频 API,甚至可用于播放前台音乐,但其主要用途是播放后台音频。使用此 API 时,存在单个全局 MediaPlayer,通过它可以进行所有播放。你的后台音频应用将向媒体播放器发送命令,以设置当前歌曲、开始播放、暂停、快进、快退等等。通过调用 MediaPlayer 类上的方法执行此操作。通过 BackgroundMediaPlayer.Current 属性访问的媒体播放器实例对象可与全局媒体播放器通信以执行音频的播放操作。
你无法创建 MediaPlayer 的新实例。
使用 SystemMediaTransportControls 类引发由通用音量控制 (UVC) 使用的事件。UVC 是在应用用户按下设备上的音量控制时显示的 UI。你可以使用 SystemMediaTransportControls 执行媒体播放器的操作。除了从应用中开始播放音频外,你还可以控制音频播放。例如,使用 SystemMediaTransportControls 在你的应用中将事件发送到 IBackgroundTask,你可以实现播放列表逻辑。本主题稍后将提供有关 IBackgroundTask 的更多讨论。
下图是一个非常简单的视图,显示了系统的设计方式。执行后台播放的应用包含两个进程。第一个进程是在前台运行的主要应用,包含了 UI。第二个进程是后台播放任务,包含了音频播放机器以及可选的某些应用逻辑。操作系统可根据其资源需求暂停或终止前台进程。后台进程将继续运行。
当在后台进程中播放音频时,前台进程将通过代理对象具有对所有信息的访问权限。前台进程可以管理后台进程中 MediaPlayer 实例的属性。前台应用可以接收特定于媒体的事件(例如 MediaOpened、MediaEnded 或 MediaFailed)的通知。在终止前台进程或暂停应用时,将继续播放媒体。
系统媒体传输控件
SystemMediaTransportControls 是在 Windows 8.1 中引入的新 API 集。Windows Phone 8.1 也可实现此类,但是由于 Windows Phone 具有一个全局音量控制,因此一次只有一个进程可与其交互。在 MediaPlayer API 的上下文中,定义后台进程中的实例和所有处理程序十分重要。这将确保该连接绑定到正确的进程,以防终止前台应用。
在任务之间发送消息
有时,你将希望在后台音频应用的两个进程之间进行通信。例如,你可能希望后台任务在开始播放新歌曲时通知前台任务,然后将新歌曲标题发送到要在屏幕上显示的前台任务。简单的通信机制可同时在前台和后台进程中引发事件。SendMessageToForeground 和 SendMessageToBackground 方法在相应的任务中分别调用事件。数据可以作为参数传递到接收的任务中的事件处理程序。使用名为 ValueSet 的新类传递数据。此类是一个字典,包含了作为键的字符串和作为值的其他值类型。你可以传递简单的值类型,例如 int、string、bool 等。
后台任务生命周期
后台任务的生命周期与应用播放音乐的能力紧密相连。例如,当用户暂停音频播放时,系统可能会根据情况终止或取消你的应用。
你的后台任务将在你的应用第一次访问前台应用代码中的 BackgroundMediaPlayer.Current 时或当你为 MessageReceivedFromBackground 事件注册处理程序时(以先发生的为准)启动。若要确保在调用 IBackgroundTask.Run 方法时建立通信通道,必须在第一次访问 BackgroundMediaPlayer.Current 属性之前注册 MessageReceivedFromBackground 事件。 在尝试启动任何音频播放之前,你的应用应该等待后台任务运行。通过此方式,你将能够订阅媒体事件。
若要使后台任务保持活动状态,你的应用必须获取 Run 方法中的 BackgroundTaskDeferral,并在任务实例接收 Canceled 或 Completed 事件时调用 BackgroundTaskDeferral.Complete。不要等待 Run 方法,因为这将使用资源并且可能会导致应用的后台任务终止。
当完成 Run 方法且未请求延迟时,你的后台任务将获取 Completed 事件。在某些情况下,当你的应用获取 Canceled 事件时,该事件后面还跟有 Completed 事件。
在以下情况下,可以取消后台任务:
- 启动带有音频播放功能的新应用。
- 如果后台任务已启动,但还未播放音乐,则前台应用将暂停。
- 如果后台任务已启动,则一段时间后,播放将暂停且前台应用将暂停。用户或其他媒体中断(例如收到一个来电或 VoIP 呼叫)可以暂停播放。如果电话呼叫或 VoIP 呼叫在 5 分钟内结束,你的应用将使用 SystemMediaTransportControlsButtonPressedEventArgs 中指示的 SystemMediaTransportControlsButton.Play 按钮接收 Run 通知。如果未结束,则用户必须使用 UVC 显式启动播放。UVC 不会丢失其状态。 但是,当用户按下“播放”按钮时,后台任务将重新启动。然后,你将获得 Run 方法调用和 SystemMediaTransportControlsButton.Play 通知。
在以下情况下,可以终止后台任务,而无需警告:
- 如果有 VoIP 呼叫打进来,但没有足够内存。
- 违反了资源策略。
- 任务取消或完成操作不会顺利结束。
后台音频最佳做法
媒体管道在本质上是异步的,这表示引发的事件只保证发生这些事件,但不保证事件顺序。例如,当你的应用从远程源获取音频文件时,该应用将获取各种更改了状态的事件,例如 Starting、Paused、Closed 等。在相同的顺序中,无需每次都调用这些处理程序。你不应该严重依赖于 CurrentStateChanged 处理程序中的 CurrentState 值。
MediaOpened 是非常重要的事件,可扮演多个角色。如果你已将 AutoPlay 设置为 false,并为 MediaPlayer 设置了源,你将仍可接收 MediaOpened。这表示媒体管道已启动,并且已准备好播放你的媒体。设置某个源时,媒体播放将自动启动。设置该源后,无需调用 Play。另一个非常好的技术是在准备好媒体后进行显式播放。通过将 AutoPlay 设置为 false,特别是在 MediaOpened 处理程序中调用 Play,可以实现此目的。
通过调用 SetUriSource、SetFileSource、SetMediaSource 或 SetStreamSource,可以将媒体源设置为几种不同类型的内容。MediaPlayer 还能够播放受保护的内容。除了设置 URI 源,该系统依赖于应用对象或内存中运行的应用代码。同样,后台进程不会注意到前台任务中的进程内存。因此,请确保你定义了所有对象,以便仅在后台进程中设置这些对象的源。如果你的应用尝试在前台进程中设置某个源(而不是 URI),则系统将引发 InvalidCastException。
BackgroundMediaPlayer.Shutdown 将关闭媒体管道,并释放内存中的 MediaPlayer 对象。如果你尝试在调用 Shutdown 后再次访问对 BackgroundMediaPlayer.Current 的引用,你将收到一个错误。Shutdown 适用于应用以在取消任务后清除媒体管道。
当你的应用暂停时,请记住从 MediaPlayer 事件取消订阅,否则你会遇到可能会导致前台进程终止的意外活动。但是,这并不意味着前台进程将离开任务切换器,用户将仍然能够返回到该应用。当应用恢复时,如果你仍然保留对暂停的 MediaPlayer 的引用,它将引发一个错误(如果后台音频任务已取消并且媒体管道已关闭)。