Windows Phone

为 Windows Phone 创建媒体应用程序

Mark Hopkins

 

Windows Phone 是使用媒体的优秀平台。 内置媒体播放器和 Windows Phone Marketplace 是音乐和我最喜欢的播客的收听材料的主要来源。 我在体育馆中、在小汽车中、在公交车上以及在一天中任何情况允许的时候收听。 我喜欢媒体应用程序,它们帮助我发现本来可能无法知道的材料。 例如,我通过内置的 Smart DJ 功能以及各种其他流音乐应用程序了解了许多新音乐。 多个应用程序允许我访问 YouTube 和 Vimeo 提供的视频内容。

如果您有兴趣为 Windows Phone 创建媒体应用程序,您需要准备许多事情以与操作系统良好集成。 具体来说,您将需要确保您的应用程序参与并出现在音乐视频中心中。

与音乐视频中心集成

“中心”为用户提供了一个便于查找内容的位置。 音乐视频中心是基于 Windows Phone 的设备上的媒体的汇集位置。 您转到这里不仅是为了查看内容,还因为它提供了对与您最相关的媒体的即时访问。 根据 Windows Phone 团队进行的研究,我们了解到用户希望执行的最常见事情是:

  1. 继续他们播放的某些内容。
  2. 到达他们最经常播放的内容。
  3. 查找他们刚添加到手机中的内容。

音乐视频中心将这三种类别的内容放在最突出的位置,同时还将媒体应用程序和本地媒体库聚集在单个体验中。 图 1 显示 Windows Phone 上的音乐视频中心的完整全景视图。

The Music + Videos Hub on Windows Phone
图 1 Windows Phone 上的音乐视频中心

除了非常适用于最终用户,音乐视频中心还为您的应用程序提供了大量价值。 它要求没有主动用户自定义,因此可轻松发现您的内容。 如果您具有提供音乐或视频内容播放的应用程序,应与音乐视频中心集成。 它是 Window Phone 体验所涉及的所有内容的重要部分。

您的应用程序可在音乐和视频体验中利用的四个关键集成点是:

  1. 填充“正在播放”磁贴。
  2. 向“新建”列表和“历史记录”列表中添加项。
  3. 确定您的应用程序是从“新建”项还是从“历史记录”项启动的。
  4. 集成到“应用程序”列表中。

填充“正在播放”磁贴

此磁贴是音乐视频中心中最突出的空间,显示当前暂停或上次播放的任何内容相对较大的图像。 点击此磁贴将继续或开始播放所显示的内容。 通过填充此图像,您可以提升您的内容并创建进入您应用程序的播放体验的其他入口点。 通过设置 MediaHistory.Instance.NowPlaying 属性来更新“正在播放”项,如以下代码段中所示(我在本文中使用 C#):

MediaHistoryItem mediaHistoryItem = new MediaHistoryItem();
// <hubTileImageStream> must be a valid ImageStream.
mediaHistoryItem.ImageStream = <hubTileImageStream>;
mediaHistoryItem.Source = "";
mediaHistoryItem.Title = "NowPlaying";
mediaHistoryItem.PlayerContext.Add("keyString", "Song Name");
MediaHistory.Instance.NowPlaying = mediaHistoryItem;

添加历史记录项

通过调用 MediaHistory.Instance.WriteRecentPlay 方法,电话上最近播放的内容可显示在“历史记录”磁贴中。 就像“正在播放”磁贴一样,“历史记录”磁贴显示图像并可点击以开始播放它所包含的内容。 下面介绍如何更新“历史记录”列表:

MediaHistoryItem mediaHistoryItem = new MediaHistoryItem();
// <hubTileImageStream> must be a valid ImageStream.
mediaHistoryItem.ImageStream = <hubTileImageStream>;
mediaHistoryItem.Source = "";
mediaHistoryItem.Title = "RecentPlay";
mediaHistoryItem.PlayerContext.Add("keyString", "Song Name");
MediaHistory.Instance.WriteRecentPlay(mediaHistoryItem);

添加“新建”项

“新建”磁贴的功能与“历史记录”磁贴的功能相同,但显示最近添加的电话内容。 例如,“新建”磁贴可能会提升刚下载到电话中的音乐文件。 不过,这些磁贴还可用于新创建的电台或播放列表之类的内容。 此处同样适用通过触摸磁贴来开始播放的相同操作。 以下代码演示如何更新“新建”列表:

MediaHistoryItem mediaHistoryItem = new MediaHistoryItem();
// <hubTileImageStream> must be a valid ImageStream.
mediaHistoryItem.ImageStream = <hubTileImageStream>;
mediaHistoryItem.Source = "";
mediaHistoryItem.Title = "MediaHistoryNew";
mediaHistoryItem.PlayerContext.Add("keyString", "Song Name");
MediaHistory.Instance.WriteAcquiredItem(mediaHistoryItem);

确定如何启动您的应用程序

“历史记录”和“新建”磁贴应该只用于开始播放,而不应该用作您的应用程序的常规启动点。 如果您的应用程序已启动并且 UI 已显示,则没有问题。 重要的是音乐或视频应通过单次点击开始,从而实现高效且一致的体验。

若要确定应用程序是从“历史记录”还是“新建”磁贴启动的,请首先替代 OnNavigatedTo 虚拟方法。 NavigationContext 中的信息用于确定与项关联的媒体,在本例中为来自设备上的媒体库的歌曲。 在页面加载完成后,该歌曲开始在 PhoneApplicationPage 的 Loaded 事件处理程序中播放。 有关这一点的详细信息,请在 MSDN 库(位于 bit.ly/y0tEiX)中下载音乐视频中心示例。

图 2 中的代码演示如何确定应用程序是从“历史记录”还是“新建”列表中的项启动的。

图 2 确定应用程序是从“历史记录”还是“新建”列表中的项启动的

// Indicates whether the app was launched from a MediaHistoryItem.
bool _historyItemLaunch = false;
// Key for MediaHistoryItem key-value pair.
const String _playSongKey = "keyString";   
// The song to play.
Song _playingSong = null;
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
  MediaLibrary library = new MediaLibrary();
  if (NavigationContext.QueryString.ContainsKey(_playSongKey))
  {
    // The app launched from a history item.
// Change _playingSong even if something was already playing
    // because the user directly chose a song history item.
// Use the navigation context to find the song by name.
String songToPlay = NavigationContext.QueryString[_playSongKey];
    foreach (Song song in library.Songs)
    {
      if (0 == String.Compare(songToPlay, song.Name))
      {
        _playingSong = song;
        break;
      }
    }
    // Set a flag to indicate that the app started from a
    // history item and that it should immediately start
    // playing the song after the UI has finished loading.
_historyItemLaunch = true;
  }
}
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e)
{
  if (_historyItemLaunch)
  {
    // Launched from a history item, start playing the song.
if (_playingSong != null)
    {
      MediaPlayer.Play(_playingSong);
    }
  }
}

与“应用程序”页面集成

如果您的应用程序调用一个或多个上述 API,则它除了显示在主应用程序列表中外,还将自动显示在中心中的“应用程序”列表中。 这使您能够更方便地查找和访问您的应用程序,并使它成为核心媒体体验的一部分。 在应用程序中心提交和认证过程检测到您的应用程序调用 MediaHistory 和 MediaHistoryItem API 并通过设置 HubType 属性更改应用程序清单以反映它是媒体应用程序时,发生此自动集成。 您可以通过更新 Windows Phone 项目中的 WMAppManifest.xml 文件中的 <App> 元素,在提交之前进行此设置—仅用于测试目的。

<App  ...
HubType="1">

在测试时,这将允许您的程序显示在“应用程序”列表中。 请注意,AppHub 提交过程将根据它检测到的将在您的应用程序中调用的 API 在发布之前覆盖此文件。

所需的图形文件

因为音乐视频中心以内容为中心,所以每个应用程序获得的空间量基于使用率。 这意味着您的应用程序的使用率越高,您的内容将越突出。 对于定期使用您的应用程序的客户,音乐视频中心将填充您的内容,从而为您提供卓越的推销商机。

因为音乐视频中心聚集了来自许多不同源的内容,所以考虑可视磁贴设计很重要,这将使您的应用程序区别于其他人的应用程序。 具体含义将视您的应用程序而定。 例如,请记住,用户将在其实际唱片集的同一列表中显示常规唱片集画面。 如果您的电台碰巧正在播放唱片集中的歌曲,则您的电台应用程序应显示与您在播放媒体库中的该歌曲时所看到的唱片集封面艺术品在视觉上不同的磁贴。 考虑使用显示您的品牌和内容艺术品的磁贴。

显示在音乐视频中心中的磁贴必须遵循以下插图规则:

  • 每个磁贴上必须包括您的应用程序标题或徽标。
  • “正在播放”磁贴必须为 358 x 358 像素。 文件大小必须为 75 KB 或更小。
  • 其他磁贴必须为 173 x 173 像素。
  • MediaHistoryItem 类的 Title 属性必须设置为表示内容的文本,例如电台名称或视频标题。

为帮助避免使用户混淆,磁贴不应包含唱片集画面,除非在按磁贴时将播放唱片集。 如果您的应用程序播放流,磁贴图形应描述正在播放的流。 虽然这不是认证要求,但它是最佳做法。

播放媒体

在播放视频时,无论您是创建 XNA Framework 还是 Silverlight 应用程序,体验都是类似的。 在 XNA Framework 应用程序中,使用 MediaPlayerLauncher 类,它在您调用 MediaPlayerLauncher.Show 时启动 Windows Phone 媒体播放器。 在 Silverlight 中,使用 MediaElement API,它允许对用户体验进行更多自定义(例如控件的外观和位置),但最终使用 Windows Phone 媒体播放器来实际显示视频。 对于音频,它更有趣一点。

MediaElement 与 SoundEffect

在 XNA Framework 应用程序中,使用 SoundEffect 类(或相关的 SoundEffectInstance 或 DynamicSoundEffectInstance 类)来播放音频。 这些类仅支持播放 WAV 音频源。 不过,您对播放具有更大的控制并可以使用一些好功能,例如能够一次播放多达 16 种声音并让它们在输出时混合在一起。

在 Silverlight 应用程序中,您可以使用 MediaElement 类在播放视频之外还播放音频。 MediaElement 支持播放 WAV、WMA、MP3 及其他音频源。 请参见 Windows Phone 支持的媒体编解码器 (bit.ly/aflZrb) 来获取 Windows Phone 上可播放的音频格式的完整列表。 MediaElement 只允许一次播放一种声音。 如果其他声音已在播放,则 MediaElement 将在您开始播放新声音时停止它。

在 Silverlight 应用程序中,您还可以使用 SoundEffect 类来播放音频。 为了在 Silverlight 应用程序中使用 XNA Framework API,您将需要模拟在 XNA Framework 应用程序中找到的游戏循环。 为此,我通常创建一个名为 StartGameLoop 的方法来设置 GameTimer。 我从 PhoneApplicationPage 派生类的构造函数中调用 StartGameLoop 方法(请参见图 3)。 GameTimer 是 Windows Phone 7.1 SDK 中提供的新类,用于促进 Silverlight 和 XNA Framework 集成。

图 3 我的 Silverlight StartGameLoop 模拟 XNA Framework 游戏循环

// Constructor
public MainPage()
{
  InitializeComponent();
   StartGameLoop();
}
private void StartGameLoop()
{
  // Timer to simulate the XNA game loop (SoundEffect
  // class is from the XNA Framework).
GameTimer gameTimer = new GameTimer();
  gameTimer.UpdateInterval = TimeSpan.FromMilliseconds(33);
  // Call FrameworkDispatcher.Update to update the XNA Framework internals.
gameTimer.Update += delegate { try { FrameworkDispatcher.Update(); } catch { } };
  // Start the GameTimer running.
gameTimer.Start();
  // Prime the pump or you'll get an exception
  // on the first XNA Framework call.
FrameworkDispatcher.Update();
}

在实现此计时器循环后,您可以在 PhoneApplicationPage 派生类中的其他位置调用 XNA Framework API。

市场认证

在应用程序调用 MediaHistory 或 MediaHistoryItem 类时,将它视为音乐视频中心应用程序,并且当安装在电话上时它会显示在“应用程序”列表中。 提交过程在 Windows Phone 应用程序清单文件中检测到应用程序使用这些类并自动将中心类型更新为音乐视频。

必须满足有关媒体播放的几个认证要求,您的应用程序才能被市场接受。 在撰写本文时,这些内容记录在 Windows Phone 的应用程序认证要求(位于 bit.ly/kN6N7Z)上的 6.4 和 6.5 节中。 认证要求随时可能会有更改并定期更新,因此对于以下任何指南,确保您了解最新版本。

认证要求规定在您的应用程序启动时,您不能中断用户正在播放的音乐。 这很有意义,因为用户可能喜欢在收听她最喜欢的音乐的同时(例如)与游戏交互。 6.5.1 和 6.5.2 节说明了此特定方案。

其他相关的是 6.5.3 节,它说明:

应用程序可能中断手机上当前播放的音乐来播放非交互式的完全运动视频或非交互式的音频段(例如, 影片剪辑或媒体剪辑)而不征求用户同意。

在应用程序关闭后,应用程序必须继续以前播放的音乐。

那么,如何暂停和重新启动用户的音乐? 如果您要创建 Silverlight 应用程序,则需要设置模拟的游戏循环,如前所述。

我尝试了暂停当前播放的音频,播放我的声音效果,然后立即重新启动以前播放的音频。 这导致了不和谐的用户体验,并确实削弱了我想要播放的声音效果的影响力。 因此我最终在用户导航到我的页面时暂停当前播放的音频,然后在用户离开时重新启动它。 我通过替代 OnNavigatedTo 和 OnNavigatedFrom 方法实现此目的。 在这些被替代的方法内,我调用帮助程序函数来暂停和重新启动音频,如图 4 中所示。

图 4 替代 OnNavigatedTo 和 OnNavigatedFrom 以暂停音频

protected override void OnNavigatedTo(NavigationEventArgs e)
{
  // If the MediaPlayer is already playing music,
  // pause it upon entering the app.
PauseMediaPlayer();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
  // If the MediaPlayer was already playing music,
  // resume playback as the user leaves the app.
ResumeMediaPlayer();
}
private void PauseMediaPlayer()
{
  // See the MainPage Constructor earlier in the
  // article where the GameTimer object is created.
// This enables the use of the XNA Framework MediaPlayer
  // class by pumping the XNA FrameworkDispatcher.
// Pause the media player if it's already playing music.
if (!MediaPlayer.GameHasControl)
  {
    MediaPlayer.Pause();
    resumeMediaPlayerAfterDone = true;
  }
}
private void ResumeMediaPlayer()
{
  // If music was playing, resume playback.
if (resumeMediaPlayerAfterDone)
  {
    MediaPlayer.Resume();
  }
}

成为好公民

总的来说,在为 Windows Phone 操作系统创建媒体应用程序时,除了处理实际媒体的具体详细信息外,还需要考虑几件事情。

确保与音乐视频中心集成,以使您的应用程序以用户希望从所有媒体应用程序获得的方式提供用户体验。 这意味着使用您的内容填充“历史记录”和“新建”磁贴并确保您的程序显示在“应用程序”列表中。

阅读并了解有关媒体应用程序的认证要求,以便您的应用程序更有可能通过 Windows Phone Marketplace 提交过程。

通过遵循这些指南,您确保用户将抢先知道如何与您的应用程序交互。 您还将提高您的应用程序和内容的可见性,方法是确保它们显示在音乐视频中心中的适当区域。 您的应用程序将是 Windows Phone 上的“好公民”。

Mark Hopkins 是 Windows Phone 开发人员文档团队的高级程序员。 他自 1992 年起在 Microsoft 工作,致力于以开发人员为中心的产品,包括开发人员支持、Visual C++、MFC、Windows Platform SDK、Internet Explorer SDK、Tablet PC SDK、Surface SDK 和 Windows Phone SDK。 他还是一名音乐家和 Seattle Sounders FC 的忠实粉丝。

衷心感谢以下技术专家对本文的审阅: Andrew ByrneKim CameronRobert LyonNitya RaviCheryl SimmonsMatt Stroshane