방법: Windows Phone의 백그라운드 오디오 재생

2012-02-09

이 항목에서는 응용프로그램이 더 이상 포그라운드에서 실행되지 않더라도 오디오 재생을 계속하는 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# 템플릿을 확장하고 Windows Phone용 Silverlight 템플릿을 선택합니다.

  3. Windows Phone 응용프로그램 템플릿을 선택합니다. 원하는 대로 이름을 입력하고 확인을 클릭합니다.

  4. 대상 버전으로 Windows Phone 7.1을 선택하고 확인을 클릭합니다.

  5. 솔루션 탐색기에서 솔루션 노드를 마우스 오른쪽 버튼으로 클릭하고 추가 | 새 프로젝트를 선택합니다.

  6. 새 프로젝트 추가 대화 상자에서 Windows Phone 오디오 재생 에이전트를 클릭합니다.

  7. 원하는 대로 이름을 입력하고 확인을 클릭합니다.

  8. 솔루션에는 이제 응용프로그램 프로젝트와 백그라운드 에이전트 프로젝트라는 2개의 프로젝트가 있습니다.

    BackgroundAudioSolution

    응용프로그램 프로젝트의 참조 노드를 마우스 오른쪽 버튼으로 클릭하고 참조 추가…를 선택합니다.

  9. 참조 추가 대화 상자에서 프로젝트 탭을 클릭합니다. 앞서 만든 백그라운드 에이전트를 선택하고 확인을 클릭합니다.

오디오 파일 추가

  1. 솔루션 탐색기에서 응용프로그램 프로젝트를 마우스 오른쪽 버튼으로 클릭하고 추가 | 새 폴더를 선택합니다. 폴더 이름을 오디오로 지정합니다.

  2. 방금 만든 오디오 폴더를 마우스 오른쪽 버튼으로 클릭하고 상황에 맞는 메뉴에서 추가 | 기존 항목을 선택합니다.

  3. 기존 항목 추가 대화 상자에서 "PUBLIC%\Music\Sample Music"(일반적으로 C:\Users\Public\Music\Sample Music)으로 이동하고 몇 개의 오디오 파일을 선택합니다. 백그라운드 오디오 플레이어가 지원하는 파일 형식에 대한 자세한 내용은 Windows Phone에 지원되는 미디어 코덱을 참조하십시오.

  4. 추가 버튼을 클릭합니다.

  5. 솔루션 탐색기에서 Audio 디렉터리에 방금 추가한 오디오 파일을 모두 선택합니다. 속성 창에서 출력 디렉터리로 복사 필드를 "복사 안 함"에서 "변경된 내용만 복사"로 변경합니다.

    BackgroundAudioAddMedia

사용자 인터페이스 만들기

  1. 이 응용프로그램의 사용자 인터페이스는 아주 단순합니다. 솔루션 탐색기에서 MainPage.xaml을 두 번 클릭하여 XAML 디자이너/편집기에서 엽니다.

  2. TitlePanel이라는 StackPanel 요소를 다음 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. ContentPanel이라는 Grid 요소를 다음 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. 다음 using 문을 MainPage.xaml.cs 파일의 맨 위에 추가합니다.

    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. 다음 using 문을 App.xaml.cs에 추가합니다.

    using System.IO.IsolatedStorage;
    using System.Windows.Resources;
    
  9. BackgroundAudioPlayer는 격리된 저장소 또는 원격 URI의 파일만 재생할 수 있습니다. App 클래스에 다음 메서드를 추가합니다. 프로젝트에 추가한 오디오 파일의 실제 이름이 파일 배열에 포함되어 있는지 확인합니다.

    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. CopyToIsolatedStorage 메서드에 대한 호출을 App 클래스의 생성자에 추가합니다.

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

AudioPlayerAgent는 사용자가 다른 포그라운드 응용프로그램으로 전환할 경우 백그라운드에서 계속 실행될 응용프로그램의 일부분입니다.

오디오 플레이어 에이전트 구현

  1. 솔루션 탐색기에서 에이전트 프로젝트의 AudioPlayer.cs를 두 번 클릭하여 코드 편집기에서 파일을 엽니다.

  2. 다음 using 문을 AudioPlayer.cs의 맨 위에 추가합니다.

    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 클래스에 다음 3개의 메서드를 추가합니다.

    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 메서드(NotifyComplete에 대한 호출 앞)에 다음 switch 문을 추가합니다.

    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 메서드(NotifyComplete에 대한 호출 앞)에 다음 switch 문을 추가합니다.

    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(Universal Volume Control)는 이 응용프로그램에서의 재생을 제어합니다. 아울러 보다 풍부한 사용자 인터페이스를 구현할 수 있도록, 웹 URI를 사용하여 원격 소스에서 오디오 파일 등으로 오디오를 재생하기 위한 더 많은 지원이 제공됩니다. 그러나 중지, 빨리 감기, 되감기 또는 검색 등의 사용자 동작에 대한 지원은 구현하지 않았습니다.

표시: