מדריך Windows Phone – השמעת מוזיקה ברקע
בפרק זה נראה כיצד נוכל לבנות אפליקציה ב Windows Phone אשר מנגנת מוזיקה, וכן ממשיכה לנגן גם כאשר האפליקציה נמצאת ברקע. נזכור שמשימה זו אינה טריוויאלית שכן אפליקציות שאינן ברקע לרוב נסגרות תוך כמה שניות ובטח שאינן יכולות להשמיע מוזיקה.
ישנם שני סוגים של אפליקציות שמנגנות מוזיקה ברקע. הסוג הראשון מנגן מוסיקה שנמצאת מקומית על המכשיר ואילו הסוג השני מנגן מדיה זורמת (Stream). בפרק זה נדבר רק על הסוג שמנגן מוזיקה מקומית, הסוג השני משתמש באותם עקרונות.
יצירת הפרויקטים הדרושים
לצורך שמיעת מוזיקה כאשר האפליקציה ברקע יש ליצור שני סוגי פרויקטים. ראשית ניצור את האפליקציה עצמה, פרויקט מסוג Windows Phone Application. בנוסף לכך, יש ליצור פרויקט מסוג Windows Phone Audio Playback Agent וכן להוסיף אותו כ Reference לפרויקט האפליקציה הראשי שלנו.
הוספת מוזיקה מקומית
כעת נוסיף קבצי מוזיקה לפרויקט של האפליקציה הראשית כדי שיהיה לנו מה לנגן. ראשית נוסיף לפרויקט ספריה חדשה בשם Audio ובתוכה נוסיף מספר קבצי מוזיקה (ע"י בחירת Add ואז Existing Item). לשם הדוגמא ניתן להשתמש בקבצים השוכנים בספריה C:\Users\Public\Music\Sample Music במחשבכם. לאחר ההוספה שנו לכל קובץ את התכונה "Copy to Output Directory" מהאפשרות "Do not copy " לאפשרות "Copy always".
יצירת ממשק משתמש
כעת ניצור ממשק משתמש לאפליקציה שלנו. נרשום בקובץ ה XAML הראשי את הקוד הבא היוצר מספר כפתורים ותיבת טקסט להצגת השיר הנוכחי.
<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>
הממשק אמור להיראות כעת כך:
הוספת פונקציונליות לאפליקציה
כעת נממש את הקוד שמאחורי הכפתורים.
ראשית נוסיף לתחילת הקובץ את השורות הבאות:
using System.Windows.Navigation;
using Microsoft.Phone.BackgroundAudio;
כעת נממש את הכפתורים באופן הבא:
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();
}
שימו לב שפעולת כפתור Play תלויה במצב הנוכחי של הנגן.
כעת נוסיף רישום לאירוע PlayStateChanged בקונסטרקטור של הדף:
public MainPage()
{
InitializeComponent();
BackgroundAudioPlayer.Instance.PlayStateChanged += 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;
}
}
הנוסף, מאחר והנגן ישמיע מוזיקה ברקע ישנה אפשרות שבעת פתיחת האפליקציה הנגן כבר מנגן משהו, לכן נוסיף קוד שיעדכן את ה UI לפי מה שנוגן בעת פתיחת האפליקציה:
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 = "";
}
}
כעת נלך לקובץ App.Xaml.cs ונוסיף את השורות הבאות בראשית הקובץ:
using System.IO.IsolatedStorage;
using System.Windows.Resources;
וכעת נוסיף את הקוד הבא שמעתיק את הקבצים מתוך ספריית ה Audio לתוך ה Isolated Storage. זה נדרש מאחר ונגן המוזיקה ברקע יודע לנגן רק מוזיקה מתוך ה Isolated Storage.
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);
}
}
}
}
}
}
לבסוף יש להוסיף קריאה לפונקציה שיצרנו מתוך הקונסטרקטור :
// Copy media to isolated storage.
CopyToIsolatedStorage();
מימוש ה Audio Agent
כעת נפתח את הקובץ AudioPlayer.cs שנוצר בפרויקט השני שיצרנו ונוסיף את השורה הבאה בתחילת הקובץ:
using System.Collections.Generic;
בנוסף נגדיר משתנה סטטי בתוך המחלקה שיזכור את מספר השיר המנוגן כעת:
// What's the current track?
static int currentTrackNumber = 0;
נכתוב פונקציה שתיצור רשימת השמעה לשירים שלנו:
// 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)
};
כעת נממש מספר פונקציות עזר:
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];
}
ונוסיף את הקוד הבא לפונקציה OnPlayStateChanged:
protected override void OnPlayStateChanged(BackgroundAudioPlayer player, AudioTrack track, PlayState playState)
{
switch (playState)
{
case PlayState.TrackReady:
// The track to play is set in the PlayTrack method.
player.Play();
break;
case PlayState.TrackEnded:
PlayNextTrack(player);
break;
}
NotifyComplete();
}
הדבר האחרון הוא להוסיף את הקוד הבא לפונקציה OnUserAction:
protected override void OnUserAction(BackgroundAudioPlayer player, AudioTrack track, UserAction action, object param)
{
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;
}
NotifyComplete();
}
זהו. קיבלנו נגן מוזיקה שיודע לנגן ולהגיב למשתמש, גם כאשר האפליקציה נמצאת ברקע.
תגובות בפייסבוק