Search code examples
performancewindows-phone-7xnamedia-player

Poor performance on song playback start in WP7


I have an XNA arcade game which runs over Silverlight environment. The game has a few sound clips which are played in random order as background music.

As stated in http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.media.songcollection.aspx, a developer cannot have full control over Media Player. Particularly, developers cannot create their song collections or add songs to the playback queue. There is a recommendation to play songs one at a time by calling MediaPlayer.Play().

That’s exactly what I'm doing but I experience a performance flaw each time when another song starts playing. The game hangs on for a moment when I call MediaPlayer.Play() despite all sound clips are loaded during game initialization, not in runtime. This happens only on some devices (e.g. HTC Mozart). In contrast, if I disable game sounds and play the same clips in phone’s music player while running the game, there are no performance issues during song changes. I also don’t experience performance problems if we play the clips using SoundEffect class. However, I'm strongly willing to use MediaPlayer for background sound purposes due to 2 reasons: - SoundEffect doesn’t issue notification when playback is completed - SoundEffect doesn’t seem to work with .mp3 files, and using .wav files is very expensive

I've also run profiling tests which confirmed that the poor performance time frame starts in a few milliseconds after MediaPlayer.Play() and continues during about 0,4 seconds. During this time my game doesn't execute any heavy-weight operations, just regular game timer's Update() function.

Here is my code snippets:

public void PlayBackgroundMusic(Song song)
{
    if ((!(App.Current as App).AppModel.SoundDisabled) && (song != null))
    {
        if (MediaPlayer.State != MediaState.Stopped)
        {
            StopBackgroundMusic();
        }
        MediaPlayer.Play(song);
    }
}

public void StopBackgroundMusic()
{
    MediaPlayer.Stop();
}

and the handler:

private void OnMediaStateChanged(object sender, EventArgs e)
{
    if (MediaPlayer.State != MediaState.Playing)
    {
        if (!AppModel.SoundDisabled)
        {
            int index = soundRandomizer.Next(0, sounds.Length - 1);
            PlayBackgroundMusic(sounds[index]);
        }
    }
}

Are there any suggestions?


Solution

  • After all, I found a solution which I'm satisfied with. It eliminates jiggling almost completely. Its idea is to use every MediaPlayer API in a separate thread obtained from thread pool. I'm not aware how it fixes the problem but this really works for me:

    public void PlayBackgroundMusic(Song song)
    {
        if ((!(App.Current as App).AppModel.SoundDisabled) && (song != null))
        {
            if (MediaPlayer.State != MediaState.Stopped)
            {
                StopBackgroundMusic();
            }
    
            ThreadPool.QueueUserWorkItem((o) =>
            {
                MediaPlayer.Play(song);
            }
        }
    }
    
    public void StopBackgroundMusic()
    {
        ThreadPool.QueueUserWorkItem((o) =>
        {
            MediaPlayer.Stop();
        }
    }