导出 (0) 打印
全部展开

如何播放 Windows Phone 的后台音频

2012/2/9

本主题演示如何为 Windows Phone 7.5 创建一个即使应用程序不再在前台运行时也继续播放音频的 Windows Phone 应用程序。有两种类型的后台音频应用程序。一个播放本地媒体,一个播放流媒体。本文介绍如何实现使用音频播放代理播放本地媒体的 Windows Phone 应用程序。

提示提示:

有关后台音频应用程序的体系结构说明,请参阅 Windows Phone 的后台音频概述。此概述还包含实现您的应用时要遵循的最佳做法。

若要播放后台音频,请在 Visual Studio 中使用 Windows Phone 的 Silverlight 项目模板创建一个“Windows Phone 音频播放代理”。然后,从您的应用程序中引用该后台代理。

提示提示:

有关在 Windows Phone 应用程序中播放后台音频的更多信息,请从 Windows Phone 的代码示例页面下载后台音频播放器示例后台音频流转化器示例

重要说明重要说明:

本文需要使用 Windows Phone SDK。请参阅安装 Windows Phone SDK

创建 Windows Phone 后台音频应用程序

  1. 通过选择“文件|新项目...”菜单命令创建一个新项目。

  2. 将显示“新建项目”对话框。展开“Visual C#”模板,然后选择“Silverlight for Windows Phone”模板。

  3. 选择“Windows Phone 应用程序”模板。根据需要填写“名称”,然后单击“确定”

  4. 选择 Windows Phone 7.1 作为目标版本,然后单击“确定”

  5. “解决方案资源管理器”中,右键单击“解决方案”节点,然后选择“添加 | 新项目...”

  6. “添加新项目”对话框中,单击“Windows Phone 音频播放代理”

  7. 根据需要填写“名称”,然后单击“确定”

  8. 现在,您的解决方案应该具有两个项目,即应用程序项目和后台代理项目。

    BackgroundAudioSolution

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

  9. “添加引用”对话框中,单击“项目”标签。选择我们之前创建的后台代理,然后单击“确定”

添加音频文件

  1. “解决方案资源管理器”中,右键单击应用程序项目,然后选择“添加 | 新文件夹”。将该文件夹命名为 Audio

  2. 右键单击您刚刚创建的 Audio 文件夹,然后从上下文菜单中选择“添加 | 现有项...”

  3. “添加现有项”对话框中,导航到“%PUBLIC%\Music\Sample Music”(通常为 C:\Users\Public\Music\Sample Music)并选择若干个音频文件。有关后台音频播放器支持的文件格式信息,请参阅支持的 Windows Phone 媒体编解码器

  4. 单击“添加”按钮。

  5. “解决方案资源管理器”中,选择您刚刚在 Audio 目录中添加的所有音频文件。在“属性”窗格中,将“复制到输出目录”字段从“Do not copy”更改为“Copy if newer”。

    BackgroundAudioAddMedia

创建用户界面

  1. 该应用程序具有一个非常简单的用户界面。在“解决方案资源管理器”中,双击“MainPage.xaml”以在 XAML 设计器/编辑器中将其打开。

  2. 将名为 TitlePanelStackPanel 元素替换为以下 XAML 代码:

    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
        <TextBlock x:Name="ApplicationTitle" Text="BACKGROUND AUDIO PLAYER" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock x:Name="PageTitle" Text="play a song" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
    
  3. 将名为 ContentPanelGrid 元素替换为此 XAML 代码:

    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <StackPanel Orientation="Horizontal" Width="420" Margin="18,40,18,0" VerticalAlignment="Top">
            <Button Content="prev" x:Name="prevButton" Height="140" Width="140" Click="prevButton_Click"/>
            <Button Content="play" x:Name="playButton" Height="140" Width="140" Click="playButton_Click"/>
            <Button Content="next" x:Name="nextButton" Height="140" Width="140" Click="nextButton_Click"/>
        </StackPanel>
        <TextBlock x:Name="txtCurrentTrack" Height="75" HorizontalAlignment="Left" Margin="12,193,0,0" VerticalAlignment="Top" Width="438" TextWrapping="Wrap" />
    </Grid>
    

    StackPanel 是用于排列按钮的非常方便的元素。在此示例中,我们通过相应地设置 Orientation 属性来水平排列按钮。

  4. 设计器中的用户界面应该如下所示:

    BackgroundAudioUI

修改用户界面的代码隐藏文件

  1. “解决方案资源管理器”中,右键单击“MainPage.xaml”,然后从上下文菜单中选择“查看代码”

  2. 向 MainPage.xaml.cs 文件的顶部添加以下 using 语句:

    using System.Windows.Navigation;
    using Microsoft.Phone.BackgroundAudio;
    
  3. 向 MainPage.xaml.cs 的 MainPage 类中添加以下按钮单击事件处理程序代码:

    #region Button Click Event Handlers
    
    private void prevButton_Click(object sender, RoutedEventArgs e)
    {
        BackgroundAudioPlayer.Instance.SkipPrevious();
    }
    
    private void playButton_Click(object sender, RoutedEventArgs e)
    {
        if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
        {
            BackgroundAudioPlayer.Instance.Pause();
        }
        else
        {
            BackgroundAudioPlayer.Instance.Play();
        }
    }
    
    private void nextButton_Click(object sender, RoutedEventArgs e)
    {
        BackgroundAudioPlayer.Instance.SkipNext();
    }
    
    #endregion Button Click Event Handlers
    

    请注意,playButton_Click 处理程序实际上根据播放的当前状态在播放和暂停之间切换。

  4. MainPage 类的构造函数中,添加 PlayStateChanged 事件的事件处理程序。

    BackgroundAudioPlayer.Instance.PlayStateChanged += new EventHandler(Instance_PlayStateChanged);
    
  5. 按照如下方式实现 Instance_PlayStateChanged 方法:

    void Instance_PlayStateChanged(object sender, EventArgs e)
    {
        switch (BackgroundAudioPlayer.Instance.PlayerState)
        {
          case PlayState.Playing:
            playButton.Content = "pause";
            break;
    
          case PlayState.Paused:
          case PlayState.Stopped:
            playButton.Content = "play";
            break;
        }
    
        if (null != BackgroundAudioPlayer.Instance.Track)
        {
          txtCurrentTrack.Text = BackgroundAudioPlayer.Instance.Track.Title +
                                 " by " +
                                 BackgroundAudioPlayer.Instance.Track.Artist;
        }
    }
    
  6. 由于该应用程序设计为在后台播放音频,因此在播放音频时用户可能会返回到该应用程序。用户界面应该通过进行相应地更新以反映播放的当前状态以及当前正在播放的曲目来显示此内容。若要在加载应用程序时更新 UI,请通过向 MainPage.xaml.cs 的 MainPage 类中添加以下代码来重写 OnNavigatedTo 虚拟方法:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        if (PlayState.Playing == BackgroundAudioPlayer.Instance.PlayerState)
        {
            playButton.Content = "pause";
            txtCurrentTrack.Text = BackgroundAudioPlayer.Instance.Track.Title +
                             " by " +
                             BackgroundAudioPlayer.Instance.Track.Artist;
    
        }
        else
        {
            playButton.Content = "play";
            txtCurrentTrack.Text = "";
        }
    }
    
  7. “解决方案资源管理器”中,右键单击“App.xaml”,然后从上下文菜单中选择“查看代码”

  8. 向 App.xaml.cs 中添加以下 using 语句:

    using System.IO.IsolatedStorage;
    using System.Windows.Resources;
    
  9. BackgroundAudioPlayer 只能播放独立存储或远程 URI 中的文件。向 App 类中添加以下方法。确保 files 数组包含您添加到项目的音频文件的实际名称。

    private void CopyToIsolatedStorage()
    {
        using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
        {
            string[] files = new string[] { "Kalimba.mp3", "Maid with the Flaxen Hair.mp3", "Sleep Away.mp3" };
    
            foreach (var _fileName in files)
            {
                if (!storage.FileExists(_fileName))
                {
                    string _filePath = "Audio/" + _fileName;
                    StreamResourceInfo resource = Application.GetResourceStream(new Uri(_filePath, UriKind.Relative));
    
                    using (IsolatedStorageFileStream file = storage.CreateFile(_fileName))
                    {
                        int chunkSize = 4096;
                        byte[] bytes = new byte[chunkSize];
                        int byteCount;
    
                        while ((byteCount = resource.Stream.Read(bytes, 0, chunkSize)) > 0)
                        {
                            file.Write(bytes, 0, byteCount);
                        }
                    }
                }
            }
        }
    }
    
  10. App 类的构造函数中添加对 CopyToIsolatedStorage 方法的调用。

    // Copy media to isolated storage.
    CopyToIsolatedStorage();
    

AudioPlayerAgent 是当用户切换到其他前台应用程序时继续在后台运行的应用程序的一部分。

实现音频播放器代理

  1. “解决方案资源管理器”中,双击代理项目中的“AudioPlayer.cs”以在代码编辑器中打开该文件。

  2. 向 AudioPlayer.cs 的顶部添加以下 using 语句:

    using System.Collections.Generic;
    
  3. AudioPlayer.cs 文件的 AudioPlayer 类中,在类作用域级别声明一个静态整数。该变量保留当前曲目编号。

    // What's the current track?
    static int currentTrackNumber = 0;
    
  4. 通过向 AudioPlayer.cs 的 AudioPlayer 类中添加以下代码创建曲目的静态列表:

    // A playlist made up of AudioTrack items.
    private static List<AudioTrack> _playList = new List<AudioTrack>
    {
        new AudioTrack(new Uri("Kalimba.mp3", UriKind.Relative), 
                        "Kalimba", 
                        "Mr. Scruff", 
                        "Ninja Tuna", 
                        null),
    
        new AudioTrack(new Uri("Maid with the Flaxen Hair.mp3", UriKind.Relative), 
                        "Maid with the Flaxen Hair", 
                        "Richard Stoltzman", 
                        "Fine Music, Vol. 1", 
                        null),
    
        new AudioTrack(new Uri("Sleep Away.mp3", UriKind.Relative), 
                        "Sleep Away", 
                        "Bob Acri", 
                        "Bob Acri", 
                        null),
    
        // A remote URI
        new AudioTrack(new Uri("http://traffic.libsyn.com/wpradio/WPRadio_29.mp3", UriKind.Absolute), 
                        "Episode 29", 
                        "Windows Phone Radio", 
                        "Windows Phone Radio Podcast", 
                        null)
    };
    

    由于该列表是在类作用域声明的,因此务必将其指定为静态,以便每次调用我们的代理时不会重新创建该列表。

  5. 若要处理诸如单击“播放”“下一个”“上一个”按钮之类的用户操作,请向 AudioPlayer.cs 的 AudioPlayer 类中添加以下三个方法:

    private void PlayNextTrack(BackgroundAudioPlayer player)
    {
        if (++currentTrackNumber >= _playList.Count)
        {
            currentTrackNumber = 0;
        }
    
        PlayTrack(player);
    }
    
    private void PlayPreviousTrack(BackgroundAudioPlayer player)
    {
        if (--currentTrackNumber < 0)
        {
            currentTrackNumber = _playList.Count - 1;
        }
    
        PlayTrack(player);
    }
    
    private void PlayTrack(BackgroundAudioPlayer player)
    {
        // Sets the track to play. When the TrackReady state is received, 
        // playback begins from the OnPlayStateChanged handler.
        player.Track = _playList[currentTrackNumber];
    }
    
  6. 若要处理播放状态更改,请向 OnPlayStateChanged 方法中添加以下 switch 语句,放在对 NotifyComplete 的调用之前:

    switch (playState)
    {
      case PlayState.TrackReady:
        // The track to play is set in the PlayTrack method.
        player.Play();
        break;
    
      case PlayState.TrackEnded:
        PlayNextTrack(player);
        break;
    }
    
  7. 若要处理用户操作,请向 OnUserAction 方法中添加以下 switch 语句,放在对 NotifyComplete 的调用之前:

    switch (action)
    {
      case UserAction.Play:
        PlayTrack(player);
        break;
    
      case UserAction.Pause:
        player.Pause();
        break;
    
      case UserAction.SkipPrevious:
        PlayPreviousTrack(player);
        break;
    
      case UserAction.SkipNext:
        PlayNextTrack(player);
        break;
    }
    

这些就是实现在后台播放音频的非常基本的应用程序所需的所有代码。该应用程序将在锁定屏幕下运行,通用音量控制 (UVC) 甚至可以从该应用程序控制播放。当然,您还可以实现更多功能,如更丰富的用户界面、支持使用音频文件的 Web URI 从远程源播放音频等等。我们还未实现对诸如停止、快进、快退、查找之类的用户操作的支持。

显示:
© 2014 Microsoft