Saturday, January 22, 2011

Gotchas when integrating with the Music and Video Hub #WP7Dev

If you are making a Windows Phone 7 app which can, or needs to, integrate with the Msuic & Video hub, Microsoft have provided some instructions on doing this:

http://windowsteamblog.com/windows_phone/b/wpdev/archive/2010/11/04/integrating-your-app-into-the-music-videos-hub.aspx
and
http://msdn.microsoft.com/en-us/library/ff769558(VS.92).aspx

There are however a few points which aren't currently (well) documented (yet):

MediaHistoryItem.Source


To integrate with the M + V Hub requires use of the MediaHistoryItem.

The MediaHistoryItem has a Source property which the Intellisense in Visual Studio tells us not to use:


If we don't set it though we get an error. Yes, even though we're told not to use it.
Infact, we have to set it to an empty string.

If we dig into the remarks for the property in MSDN we do find a note about this:
"Although this property is unsupported, you must set its value to "", meaning a blank string, whenever you instantiate a new MediaHistoryItem."

MediaHistoryItem.Title


Another property of the MediaHistoryItem is Title. This is a required property.

At this point it should be noted that there are 3 occasions to use the MediaHistoryItem: When adding a new item; When updating the Now Playing item; and when updating the recently played list.
For all of these scenarios you must set the Title to something, but it's only actually used when setting the "NowPlaying" item.


MediaHistoryItem.ImageStream


When specifying the stream of the image to use for the tile in the M + V hub, there is documentation about the Application Certification Requirements with regards to the images that are used but somewhat unhelpfully it's easy to miss that the stream must be smaller than the undocumented MaxImageSize.
This size is just 16KB.

System.ArgumentException: image stream size bigger than maximum allowed 16384

This may seem quite large for a an image just 358x358 or 173x173 pixels in size. (Your image will be resized and/or cropped if not the specified dimensions - but you may not get through Marketplace certification if you rely on this.)
You may hit an issue if you are using a complex image for the tile (which you have if using album artwork or a packshot image) and wish to maintain a high quality image.
If you have this issue you may wany to consider using a solider colour border around the image to allow you to maintain a higher image quality (meaning lower jpeg compression is needed).

MediaPlayerLauncher & WMDRM


MediaPlayerLauncher makes it easy to play WMV files from IsolatedStorage:

    var mpl = new MediaPlayerLauncher
                    {
                        Controls = MediaPlaybackControls.All,
                        Location = MediaLocationType.Data,
                        Media = new Uri("filename.wmv", UriKind.Relative)
                    };

    mpl.Show();

But if you're WMV file uses WMDRM, rather than PlayReady DRM then things get tricky.

Unfortunately, Silverlight doesn't support WMDRM, only PlayReady DRM.
Fortunately, Silverlight provides a way to override the use of WMDRM and use a PlayReady license server instead.
Unfortunatley, MediaPlayerLauncher doesn't support this.
Fortunately, one of the features of Silverlight 4 which was included in Silverlight on WP7 was the ability to support persistent PlayReady DRM licenses.

So what can we do?

Assuming we're able to issue persistent PlayReady licenses (a separate issue I won't discuss now) we can combine the use of MediaPlayerLauncher with the use of MediaElement.

We can use the MediaElement (which includes a LicenseAcquirer and in turn the LicenseServerUriOverride property) to get a PlayReady license.



    forLicenseAcquisition.LicenseAcquirer.LicenseServerUriOverride =
        new Uri(AppResources._RightManagerAddress + urlGetParams, UriKind.Absolute);

    using (var store = IsolatedStorageFile.GetUserStoreForApplication())
    {
        var movieFileStream = store.OpenFile("filename.wmv", FileMode.Open, FileAccess.Read);
        forLicenseAcquisition.SetSource(movieFileStream);

        forLicenseAcquisition.Play();
    }

Once the license has been received the MediaElement will start to play. We can then handle the event raised when the MediaElement starts to play.
In that handler we stop the playing via the MediaElement and then start it in the MediaPlayerLauncher.

    private void forLicenseAcquisition_MediaOpened(object sender, RoutedEventArgs e)
    {
        forLicenseAcquisition.Stop();

        // record that license acquired

        var mediaHistoryItem = new MediaHistoryItem();
        mediaHistoryItem.Title = "My Movie";
        mediaHistoryItem.Source = string.Empty; // Must be set but unused

        using (var store = IsolatedStorageFile.GetUserStoreForApplication())
        {
            mediaHistoryItem.ImageStream = store.OpenFile("tile_image.jpg", FileMode.Open, FileAccess.Read);
        }

        mediaHistoryItem.PlayerContext.Add("Movie_Title", "My Movie");

        MediaHistory.Instance.NowPlaying = mediaHistoryItem;

        var mpl = new MediaPlayerLauncher
        {
            Controls = MediaPlaybackControls.All,
            Location = MediaLocationType.Data,
            Media = new Uri("filename.wmv", UriKind.Relative)
        };

        mpl.Show();
    }

This only works with a persistent license though. I don't see this being too much of an issue though as if the content is being loaded onto the device (phone) then the owner of the phone should (I would argue) be allowed to play the content at any time, even if they're not able to connect to the PlayReady server. (They will still need that connection the first time though.)

If doing this, it's also wise to handle the MediaElement Failed event in case there is a problem getting the license.
It's also wise to keep track of which content a license has been acquired for. This means that you can skip the need to use a MediaElement on future attempts to play the content. This means that content can be loaded and therefore start playing faster on subsequent times.

I hope someone will find the above useful. ;)

3 comments:

  1. Hi,
    I am trying it hard to build a SL4 media client which would play WMDRM protected video. I understand that we need a PlayReady License server as SL4 understands only PlayReady License.

    I have WMDRM encrypted video files and its license file hosted in IIS7.
    I have a PlayReady License Server SL4 Media Client with LicenseAcquirer URL pointing to PlayReady License Server(the uri override stuff).

    But was wondering What configuration needs to be done on the PlayReady License Server to deliver WMDRM Licenses? Any help in this direction would be of great help. thx K

    ReplyDelete
  2. @paandian The PlayReady Server will issue PlayReady Licenses, not WMDRM ones as it's this type of license that the PlayReady Players can understand.

    After overriding the License Uri you need the server to create a new MediaLicense and add that to the response. Being sure to bind the license key and adding appropriate rights.
    Obviously only doing this after validating the challengeData in the same way you would before issuing the WMDRM license.

    Check the sample and documentation in the PlayReady SDK from more details.

    ReplyDelete
  3. Anonymous1:20 pm

    Hello Matt,

    Do you know does SSME (Smooth Streaming MediaElement) on WP7 support PlayReady DRM? Any article or example code?

    Kevin Kao

    ReplyDelete

I get a lot of comment spam :( - moderation may take a while.