Windows Phone 的后台音频概述

2012/2/9

从 Windows Phone OS 7.1 开始,您可以编写在后台播放音频的应用程序。这意味着,即使用户已通过按“返回”按键或“开始”按键离开您的应用程序,您的应用程序也可以继续播放音频。本文介绍为了创建后台音频应用程序而需要实现的部分以及这些部分如何协同工作。

提示提示:

后台音频播放器示例后台音频流转化器示例的源代码可用于 Windows Phone 的代码示例页面。

也可以获得 MediaStreamSource 示例的源代码。

请参阅如何播放 Windows Phone 的后台音频

后台音频应用程序利用后台代理(Windows Phone OS 7.1 中的新增内容)。有关后台代理的更多信息,请参阅 Windows Phone 多任务处理功能

Windows Phone 上的所有媒体都是通过 Zune 媒体队列播放的。后台音频应用程序向 Zune 媒体队列发送命令以设置当前堆栈、开始播放、暂停、快进、后退等。通过在 BackgroundAudioPlayer 类中调用方法来完成该操作。然后,Instance 对象与 Zune 媒体队列通信以操作音频的播放。

通用音量控制 (UVC) 是一组控件,当正在播放音频或当用户按音量控制开关时显示这些控件。UVC 还操作 Zune 媒体队列。因此,当您随后从应用程序开始播放某些内容时,可以使用 UVC 控制音频。UVC 向您应用程序中的 AudioPlayerAgent 发送事件,从而允许您实现播放列表逻辑。将在本主题的后面部分对 AudioPlayerAgent 进行详细讨论。

有两种类型的后台音频应用程序。一种类型实现简单的播放列表并将一个包含媒体文件地址的 URI 传递给 Zune 媒体队列以设置当前曲目。URI 可以是手机的本地或远程地址。在任何一种情况下,音频需要是 Windows Phone 支持的类型才能播放。有关有效的视频文件类型,请参阅支持的 Windows Phone 媒体编解码器

另一种类型的后台音频应用程序使用 MediaStreamSource 实现音频流以向播放系统输送音频示例。此流的格式可以是您需要的任何格式,因为您实现一个从 MediaStreamSource 派生的类来处理音频的流处理以及对音频的解码。实现 MediaStreamSource 不在本文的讨论范围内。有关更多信息,请参阅实现 MediaStream 源

这两种类型的应用程序共享多个部分。我们将开始讨论实现播放列表的应用程序。然后,我们将讨论使用 MediaStreamSource (MSS) 实现流处理的部分。

播放列表应用程序

若要创建后台音频播放列表应用程序,您必须实现两个部分:提供用于控制播放的用户界面的应用程序和实现从 AudioPlayerAgent 派生的类的程序集。您必须实现的这两个部分在下图中以绿色显示。

后台音频播放列表应用程序体系结构

应用程序 UI

应用程序用户界面是您实现您应用程序的用户界面的位置。如果您使用 Visual Studio 模板创建您的初始应用程序,则该应用程序将在 MainPage.xaml 和 MainPage.xaml.cs 文件中。您的主应用程序使用 Instance 设置 Zune 媒体队列中的当前曲目,启动播放等等。

AudioPlayerAgent

您的 AudioPlayerAgent 由操作系统进行实例化,以通过您应用程序的用户界面或通过 UVC 处理用户所请求的操作。

您的 AudioPlayerAgent 在后台运行并调用 BackgroundAudioPlayer 的实例,该实例随后调用 Zune 媒体队列以实际播放音频。

您的代理完成处理 OnUserAction(BackgroundAudioPlayer, AudioTrack, UserAction, Object)OnPlayStateChanged(BackgroundAudioPlayer, AudioTrack, PlayState)OnError(BackgroundAudioPlayer, AudioTrack, Exception, Boolean) 之后,调用 NotifyComplete()()()() 以让操作系统知道您已完成并且可以安全地从内存中删除代理。

使用 Visual Studio 中的“Windows Phone 音频播放代理”模板创建新的 AudioPlayerAgent 项目并将该项目添加到您的解决方案中。

后台音频播放代理模板

然后,从主应用程序项目中添加对新 AudioPlayerAgent 的引用。

BackgroundAudioSolution

右键单击应用程序项目中的“引用”节点,然后选择“添加引用...”

对音频应用程序进行流处理

若要创建流音频应用程序,您必须实现与播放列表应用程序相同的部分。具体来说,就是您必须创建一个提供用户界面的主应用程序,以及一个 AudioPlayerAgent。对于流音频应用程序,您还必须实现从 AudioStreamingAgent 派生的一个类以及从 MediaStreamSource 派生的一个类。您必须实现的这些部分在下图中以绿色显示。

后台音频流应用程序体系结构

音频流代理

AudioStreamingAgent 负责通过在传递到 OnBeginStreaming(AudioTrack, AudioStreamer) 方法的 AudioStreamer 实例上调用 SetSource(MediaStreamSource) 来创建并将 Zune 媒体队列指向 MediaStreamSource

使用 Visual Studio 中的“Windows Phone 音频流代理”模板创建新的 AudioStreamingAgent 项目并将该项目添加到您的解决方案中。

后台音频流代理模板

MediaStreamSource

Zune 媒体队列调用您的 MediaStreamSource 来请求音频示例。创建 MediaStreamSource 不在本主题的讨论范围内。有关更多信息,请参阅实现 MediaStream 源MediaStreamSource 示例

后台代理生命周期

您的 AudioPlayerAgent 是由 BackgroundAudioPlayer 在需要时创建的,用于处理来自您应用程序的用户界面或来自 UVC 的 UserAction 请求。

您的 AudioStreamingAgent 是由 BackgroundAudioPlayer 在需要新流时创建的。创建代理之后,BackgroundAudioPlayer 在您的 AudioStreamingAgent 中调用 OnBeginStreaming(AudioTrack, AudioStreamer) 方法。

当后台代理调用 Abort()()()()NotifyComplete()()()() 时释放后台代理。

其他后台音频类

后台音频应用程序利用其他类来实现音频播放器体验。

BackgroundAudioPlayer

BackgroundAudioPlayer 类与 Zune 媒体队列连接。在 Instance 上调用方法以影响设备上正在播放的音频。

AudioTrack

AudioTrack 类表示有关某个曲目的元数据,包括标题、艺术家、专辑以及曲目的 URI。如果 URI 设置为 null,则系统假定您将曲目设置为 MediaStreamSource。在这种情况下,您可以使用 Tag 属性将 AudioPlayerAgent 中的信息传递给 AudioStreamingAgent

AudioStreamer

AudioStreamer 的实例传递给 OnBeginStreaming(AudioTrack, AudioStreamer)。在 OnBeginStreaming 的实现中,调用 SetSource(MediaStreamSource) 以指向从 MediaStreamSource(提供音频示例)派生的一个类。

本节详细介绍了创建播放后台音频的应用程序时要实现的一些最佳做法。

调试

在编码、调试、编辑代码和重新启动调试的过程中,调试器可能会在您重新启动调试时将自身连接到后台音频代理,而不是您的应用程序。若要避免出现这种情况,您需要确保后台代理在应用程序启动时处于关闭状态。要实现这一点,有一种简便的方法是将对 Close()()()() 的调用放到 App 类的构造函数中。如果您是通过 Visual Studio 模板创建的应用,则 App 类构造函数中会包含一项检查,以了解该应用程序是否正在调试器下运行。可将对 BackgroundAudioPlayer.Instance.Close 的调用放在此 if 语句中。

// Show graphics profiling information while debugging.
if (System.Diagnostics.Debugger.IsAttached)
{
    // Close the background audio player in case it 
    // was running from a previous debugging session.
    BackgroundAudioPlayer.Instance.Close();

    // ...

处理用户操作

BackgroundAudioPlayer 未对 UserAction 请求的数量施加任何限制。通过 UI(通过您的应用或通用音量控制 (UVC))调用的操作排成队列并一个个地进行处理。AudioPlayerAgent 没有确定是否存在连续调用的方法。需要网络请求的 SkipNextSkipPreviousPlay 调用可能需要几秒钟的时间。

对用户体验的影响是:

  1. 无论调用花费的时间长短,都将按顺序处理对 SkipNextSkipPreviousPlay 的连续调用。

  2. 每次调用允许 30 秒的时间。

  3. 由于 PlayPause 操作未获得优先权,因此代理可能花费几秒钟(甚至几分钟)的时间才能响应用户操作。这与立即响应 PlayPause 的预期用户体验产生矛盾。

因此限制排队的 SkipNextSkipPrevious 请求的数量并给予 PlayPause 较高的优先级。后台音频播放器示例只是在处理请求之前禁用“下一个”“上一个”按钮。从 Windows Phone 的代码示例页面中获得后台音频播放器示例的代码。

MediaElement 和 BackgroundAudioPlayer

混合 BackgroundAudioPlayerMediaElement 进行音频播放时,要十分小心。

  1. 必须在切换到 MediaElement 播放之前调用 Close()()()()

  2. 只有一个媒体队列。您的应用程序不能暂停后台音频,不能使用 MediaElement 播放某些内容,而且不能继续播放后台音频流。

内存和运行时约束

  • AudioPlayerAgent 的实现必须在 30 秒内调用 NotifyComplete()()()()Abort()()()()

  • AudioStreamingAgent 的实现则允许无限时运行。

  • 两种类型的后台音频代理都托管在同一进程中,并且共用最大限制为 15 MB 的内存。

  • 在调试器下运行时,Windows Phone 操作系统会忽略内存和运行时约束。

显示: