Building Audio/Video Applications based on Player Framework v2.0 for Windows Phone 8, Windows 8.1 and Windows Phone 8.1

INTRODUCTION

This article describes the different steps  to create Windows Phone 8, Windows 8.1 and Windows Phone 8.1 applications playing video supporting the following formats:  
- Step 1: WMV, MP4, MPEG2-TS (only for Windows 8.1)    
- Step 2: WMV, MP4, MPEG2-TS (only for Windows 8.1) and Smooth Streaming     
- Step 3: WMV, MP4, MPEG2-TS (only for Windows 8.1), Smooth Streaming and MPEG DASH    
- Step 4: WMV, MP4, MPEG2-TS (only for Windows 8.1), Smooth Streaming and MPEG DASH protected with PlayReady    
The sample applications delivered with this article allow the user to define:    
- the video Uri,    
- the PlayReady license acquisition Uri,    
- the « Challenge Custom Data » for the PlayReady license acquisition.
If the PlayReady license acquisition Uri is not defined, the application will use the Uri defined in protection header of the manifest.
By default the applications use a list of videos supporting the different formats.
         image_thumb4                                                              image_thumb5
              Windows Phone 8                                                                           Windows Phone 8.1

                        image_thumb3

                                                                           Windows 8.1
image_thumb35

STEP 1: AUDIO/VIDEO PLAYER (WMV, MP4, MPEG2-TS)

The Windows Phone 8, Windows 8.1 and Windows Phone 8.1 Applications for Step 1 support the following formats:
- Windows: WMV, MP4, MPEG2-TS
- Windows Phone : WMV, MP4

Those formats are natively supported, no supplementary SDKs are required.

image_thumb9

Windows 8.1, Windows Phone 8.1 and Windows Phone 8.0 Applications:

On the XAML MainPage insert the MediaElement and call it « Player »   

 <MediaElement x:Name="Player" Grid.Row="1" Grid.Column="2" Grid.RowSpan="4" Grid.ColumnSpan="1"
Stretch="Uniform" Margin="20,10,20,10" HorizontalAlignment="Center" VerticalAlignment="Center" />

In the method associated with Click event on button “Play”, initialize Player Source with the Uri of the video you want to play  

 Player.Source = new Uri(MediaUri.Text);

Sample Uris compliant with WMV, MP4 and MPEG2-TS format are available on Microsoft Azure

 
https://livestreamingvm.cloudapp.net/vod/wmv/test1.wmv
https://livestreamingvm.cloudapp.net/vod/mp4/test1.mp4
https://livestreamingvm.cloudapp.net/vod/ts/test1.ts

STEP 2: AUDIO/VIDEO PLAYER (WMV, MP4, MPEG2-TS, SMOOTH STREAMING)

The Windows Phone 8, Windows 8.1 and Windows Phone 8.1 Applications for Step 2 support the following formats:

- Windows: WMV, MP4, MPEG2-TS and Smooth Streaming 
- Windows Phone : WMV, MP4 and Smooth Streaming

Supplementary SDKs are required to build the applications :

 image_thumb37

Windows 8.1 and Windows Phone 8.1 Applications:

Add a reference to « Microsoft Smooth Streaming Client SDK for Windows 8.1 » for Windows 8.1 application.

image_thumb13

Add a reference to « Microsoft Smooth Streaming Client SDK for Windows Phone 8.1 » for Windows Phone 8.1 application.

image_thumb14

On the XAML MainPage insert the MediaElement and call it  « Player »

 
<MediaElement x:Name="Player" Grid.Row="1" Grid.Column="2" 
Grid.RowSpan="4" Grid.ColumnSpan="1"
Stretch="Uniform" Margin="20,10,20,10" 
HorizontalAlignment="Center" VerticalAlignment="Center" />

Create a method RegisterPlugins which associates the Smooth Streaming library with the Smooth Streaming Uri opened by the MediaElement. This method is called in the method OnNavigatedTo.

 public Windows.Media.MediaExtensionManager MediaManager;
public IAdaptiveSourceManager AdaptiveSrcManager { get; private set; }
void RegisterPlugins()
{
     LogMessage("Register plugins");
     if (MediaManager == null)
                MediaManager = new Windows.Media.MediaExtensionManager();
     if (AdaptiveSrcManager == null)
                AdaptiveSrcManager = AdaptiveSourceManager.GetDefault();
     PropertySet ssps = new PropertySet();
     ssps["{A5CE1DE8-1D00-427B-ACEF-FB9A3C93DE2D}"] = AdaptiveSrcManager;


     MediaManager.RegisterByteStreamHandler("Microsoft.Media.AdaptiveStreaming.SmoothByteStreamHandler", ".ism", "text/xml", ssps);
     MediaManager.RegisterByteStreamHandler("Microsoft.Media.AdaptiveStreaming.SmoothByteStreamHandler", ".ism", "application/vnd.ms-sstr+xml", ssps);
     MediaManager.RegisterByteStreamHandler("Microsoft.Media.AdaptiveStreaming.SmoothByteStreamHandler", ".isml", "text/xml", ssps);
     MediaManager.RegisterByteStreamHandler("Microsoft.Media.AdaptiveStreaming.SmoothByteStreamHandler", ".isml", "application/vnd.ms-sstr+xml", ssps);
     MediaManager.RegisterSchemeHandler("Microsoft.Media.AdaptiveStreaming.SmoothSchemeHandler", "ms-sstr:", ssps);
} 

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    LogMessage("OnNavigatedTo");
    base.OnNavigatedTo(e);
    Application.Current.Suspending += App_Suspending;
    Application.Current.Resuming += App_Resuming;
    Player.MediaEnded += Player_MediaEnded;
    Player.MediaOpened += Player_MediaOpened;
    Player.MediaFailed += Player_MediaFailed;
#if WINDOOWS_PHONE_APP
    DisplayInformation.GetForCurrentView().OrientationChanged += OnOrientationChanged;
#endif
    RegisterPlugins();
}

In the method associated with Click event on button “Play”, initialize Player Source with the Uri of the video you want to play

 Player.Source = new Uri(MediaUri.Text);

Sample Uris compliant with Smooth Streaming format are available on Microsoft Azure

 
https://livestreamingvm.cloudapp.net/vod/test1/test1.ism/manifest

Applications Windows Phone 8.0:

Add a reference to « Microsoft.Web.Media.SmoothStreaming » for Windows Phone 8.0 application.

image_thumb15

On the XAML MainPage :

- insert the MediaElement used to play WMV, MP4 content and call it « Player »

- insert the SmoothStreamingMediaElement used to play Smooth Streaming content and call it « PlayerSSME »

 <MediaElement Visibility="Visible" x:Name="Player" Grid.Row="3" 
Stretch="Uniform" Grid.Column="0" Grid.ColumnSpan="3" Margin="10,10,10,10" 
HorizontalAlignment="Center" VerticalAlignment="Center" />
<ssme:SmoothStreamingMediaElement Visibility="Collapsed" 
x:Name="PlayerSSME" Grid.Row="3" Stretch="Uniform" Grid.Column="0" 
Grid.ColumnSpan="3" Margin="10,10,10,10" HorizontalAlignment="Center" 
VerticalAlignment="Center" />

In the method associated with Click event on button “Play”, initialize PlayerSSME SmoothStreamingSource with the Uri of the smooth streaming video you want to play, if you want to play MP4 or WMV video, initialize Player Source with the Uri of the WMV or MP4 video.

 if (MediaUri.Text.EndsWith("/manifest", StringComparison.CurrentCultureIgnoreCase))
    PlayerSSME.SmoothStreamingSource = new Uri(MediaUri.Text);
else 
    Player.Source = new Uri(MediaUri.Text);

Sample Uris compliant with Smooth Streaming format are available on Microsoft Azure

 
https://livestreamingvm.cloudapp.net/vod/test1/test1.ism/manifest

STEP 3: AUDIO/VIDEO PLAYER (WMV, MP4, MPEG2-TS, SMOOTH STREAMING, MPEG DASH)

The Windows Phone 8, Windows 8.1 and Windows Phone 8.1 Applications for Step 3 support the following formats:

- Windows: WMV, MP4, MPEG2-TS, Smooth Streaming  and MPEG DASH 
- Windows Phone : WMV, MP4, Smooth Streaming  and MPEG DASH

Supplementary SDKs are required to build the applications :

image_thumb17

Windows 8.1 and Windows Phone 8.1 Applications:

Add a reference to:

« Microsoft Smooth Streaming Client SDK for Windows 8.1 »,

« Microsoft Player Framework », 
« Microsoft Player Framework Adaptive Streaming Plugin», 
« Microsoft Player Framework Dash Plugin» for Windows 8.1 application.

image_thumb18

Add a reference to:

« Microsoft Smooth Streaming Client SDK for Windows Phone 8.1 »,

« Microsoft Player Framework »,

« Microsoft Player Framework Adaptive Streaming Plugin»,

« Microsoft Player Framework Dash Plugin» for Windows Phone 8.1 application.

image_thumb19

On the XAML MainPage insert the « PlayerFramework:MediaPlayer » and call it « Player »

 <PlayerFramework:MediaPlayer x:Name="Player" Grid.Row="1" Grid.Column="2" Grid.RowSpan="4" Grid.ColumnSpan="1" Margin="20,10,20,10"         
            IsTimelineVisible="false" IsTimeElapsedVisible="false" IsDurationVisible="false" IsTimeRemainingVisible="false« 
            IsInfoVisible="false"  IsMoreVisible="false«  IsFastForwardVisible="False" IsRewindVisible="False"
            IsSkipBackVisible="False" IsSkipAheadVisible="False"  IsSkipPreviousVisible="False"   IsReplayVisible="False"  
            IsAudioSelectionVisible="False" IsCaptionSelectionVisible="False" HorizontalAlignment="Center"  VerticalAlignment="Center"  
            IsFullScreenVisible="True" Background="Black"  />

Create a method RegisterPlugins which associates the Adaptive plugin with the Smooth Streaming Uri opened by the Player. This method is called in the method OnNavigatedTo.  Create a method RegisterDashPlugins which associates the DashDownloaderPlugin plugin with the Adaptive plugin used by the Player. This method is called before playing any MPEG DASH content.

 
public Microsoft.PlayerFramework.Adaptive.AdaptivePlugin adaptivePlugin;
public Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin dashDownloaderPlugin;

void RegisterDashPlugin(bool bRegister)
{
    Microsoft.PlayerFramework.Adaptive.AdaptivePlugin plugin = Player.Plugins.OfType<Microsoft.PlayerFramework.Adaptive.AdaptivePlugin>().First();
    if (plugin != null)
    {
        if (bRegister == true)
        {
            LogMessage("Register DASH plugin");
            if (dashDownloaderPlugin == null)
                dashDownloaderPlugin = new Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin();
            plugin.DownloaderPlugin = dashDownloaderPlugin;
        }
        else
        {
            LogMessage("Unregister DASH plugin");
            plugin.DownloaderPlugin = null;
        }
    }
}
void RegisterPlugins()
{
    LogMessage("Register plugins");

    if (adaptivePlugin == null)
        adaptivePlugin = new Microsoft.PlayerFramework.Adaptive.AdaptivePlugin();

    Player.Plugins.Add(adaptivePlugin);
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    LogMessage("OnNavigatedTo");
    base.OnNavigatedTo(e);
    Application.Current.Suspending += App_Suspending;
    Application.Current.Resuming += App_Resuming;
    Player.MediaEnded += Player_MediaEnded;
    Player.MediaOpened += Player_MediaOpened;
    Player.MediaFailed += Player_MediaFailed;
#if WINDOWS_PHONE_APP
    DisplayInformation.GetForCurrentView().OrientationChanged += OnOrientationChanged;
#endif
    RegisterPlugins();
}

In the method associated with Click event on button “Play”, call the method RegisterDashPlugin to register the DashDownloaderPlugin (if it’s a MPEG DASH uri), and then initialize Player Source with the Uri of the video you want to play.

 RegisterDashPlugin((MediaUri.Text.EndsWith(".mpd", StringComparison.CurrentCultureIgnoreCase) || 
                     MediaUri.Text.EndsWith("manifest(format=mpd-time-csf)", StringComparison.CurrentCultureIgnoreCase)));
Player.Source = new Uri(MediaUri.Text);

Sample Uris compliant with MPEG DASH format are available on Microsoft Azure.

 https://wams.edgesuite.net/media/SintelTrailer_Smooth_SeekDemo/sintel_trailer-1080p.ism/manifest(format=mpd-time-csf)

Applications Windows Phone 8.0:

Add a reference to:

« Microsoft.Web.Media.SmoothStreaming »,

« Microsoft Player Framework »,

« Microsoft Player Framework Adaptive Streaming Plugin»,

« Microsoft Player Framework Dash Plugin» for the Windows Phone 8.0 application<

image_thumb20

On the XAML MainPage insert the « PlayerFramework:MediaPlayer » and call it « Player »

 <PlayerFramework:MediaPlayer  Visibility="Visible" x:Name="Player"  Grid.Row="3" Grid.Column="0" 
Grid.ColumnSpan="3"  Grid.RowSpan="1"  Margin="10,10,10,10" Background="Black" Foreground="Black" 
IsAudioSelectionVisible="False" IsCaptionSelectionVisible="False"     HorizontalAlignment="Center"  VerticalAlignment="Center"  IsFullScreenVisible="False" />

Create a method RegisterPlugins which associates the Adaptive plugin with the Smooth Streaming Uri opened by the Player. This method is called in the method OnNavigatedTo.  Create a method RegisterDashPlugins which associates the DashDownloaderPlugin plugin with the Adaptive plugin used by the Player. This method is called before playing any MPEG DASH content.

 public Microsoft.PlayerFramework.Adaptive.AdaptivePlugin adaptivePlugin;
public Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin dashDownloaderPlugin;

void RegisterDashPlugin(bool bRegister)
{
    Microsoft.PlayerFramework.Adaptive.AdaptivePlugin plugin = Player.Plugins.OfType<Microsoft.PlayerFramework.Adaptive.AdaptivePlugin>().First();
    if (plugin != null)
    {
        if (bRegister == true)
        {
            LogMessage("Register DASH plugin");
            if (dashDownloaderPlugin == null)
                dashDownloaderPlugin = new Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin();
            plugin.DownloaderPlugin = dashDownloaderPlugin;
        }
    }
}
void RegisterPlugins()
{
    LogMessage("Register plugins");
    if (adaptivePlugin == null)
        adaptivePlugin = new Microsoft.PlayerFramework.Adaptive.AdaptivePlugin();
    Player.Plugins.Add(adaptivePlugin);
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    LogMessage("OnNavigatedTo");
    base.OnNavigatedTo(e);
    PhoneApplicationService.Current.Deactivated += App_Suspending;
    PhoneApplicationService.Current.Activated += App_Resuming;
    Player.MediaEnded += Player_MediaEnded;
    Player.MediaOpened += Player_MediaOpened;
    Player.MediaFailed += Player_MediaFailed;
    RegisterPlugins();
}

In the method associated with Click event on button “Play”, first initialize the Player Source with null and close the player. Then call the method RegisterDashPlugin to register the DashDownloaderPlugin (if it’s a MPEG DASH Uri), and then initialize Player Source with the Uri of the video you want to play.

 
Player.Source = null;
Player.Close();

RegisterDashPlugin((MediaUri.Text.EndsWith(".mpd", StringComparison.CurrentCultureIgnoreCase) || 
                     MediaUri.Text.EndsWith("manifest(format=mpd-time-csf)", StringComparison.CurrentCultureIgnoreCase)));
Player.Source = new Uri(MediaUri.Text);

Sample Uris compliant with MPEG DASH format are available on Microsoft Azure.

 https://wams.edgesuite.net/media/SintelTrailer_Smooth_SeekDemo/sintel_trailer-1080p.ism/manifest(format=mpd-time-csf)

STEP 4: AUDIO/VIDEO PLAYER (WMV, MP4, MPEG2-TS, SMOOTH STREAMING, MPEG DASH, PLAYREADY)

The Windows Phone 8, Windows 8.1 and Windows Phone 8.1 Applications for Step 4 support the following formats:

- Windows: WMV, MP4, MPEG2-TS, Smooth Streaming and MPEG DASH protected or not with PlayReady  DRM

- Windows Phone : WMV, MP4, Smooth Streaming and MPEG DASH protected or not with PlayReady DRM

Supplementary SDKs are required to build the applications :

image_thumb22

Steps to acquire a PlayReady license for Universal Apps (Windows 8.1 et Windows Phone 8.1) :

Before describing how the PlayReady client acquires the PlayReady license, some words about the Individualization. Every PlayReady client has a unique digital certificate and key, the installation of the certificate and the key is called Individualization.

Moreover, before the PlayReady client requests the license to decrypt the content, it must first determine whether the user’s computer has the appropriate PlayReady software installed. This software is called the Individualized Black boX (IBX) and is the client component of PlayReady that is required before any protected content can be played. The individualization component software enables the client computer to request and use a PlayReady license.

The PlayReady client for Windows Store applications supports dynamic individualization: the IBX is downloaded from the Individualization Server. In your application you can implement a Pro-Active Individualization Request or a Reactive Individualization Request.

  • A Pro-Active Individualization Request can be transmitted just after the installation of the application or when the user launches the application for the first time.
  • A Reactive Individualization Request is automatically prepared by the PlayReady client when the application is about to play an asset protected with PlayReady and if the IBX is not installed on the computer.

The schema below describes the acquisition of a PlayReady license to play an asset protected with PlayReady with a Reactive Individualization Request: 

image_thumb24  

The schema below describes the acquisition of a PlayReady license to play an asset protected with PlayReady without any Individualization Request as the Individualized Black Box (IBX) is already installed: 

image_thumb26

The schema below describes the exchanges between the client and the server when the application plays an asset protected with PlayReady when the Individualized Black Box (IBX) is already installed and the PlayReady license has already been acquired and the license is persistent: 

image_thumb28

Windows 8.1 and Windows Phone 8.1 applications:
Add a reference to:

« Microsoft Smooth Streaming Client SDK for Windows 8.1 », 
« Microsoft Player Framework », 
« Microsoft Player Framework Adaptive Streaming Plugin», 
« Microsoft Player Framework Dash Plugin», 
« Microsoft PlayReady Client SDK» for Windows 8.1 application.

image_thumb29

Add a reference to:

« Microsoft Smooth Streaming Client SDK for Windows Phone 8.1 », 
« Microsoft Player Framework », 
« Microsoft Player Framework Adaptive Streaming Plugin», 
« Microsoft Player Framework Dash Plugin», 
« Microsoft PlayReady Client SDK» for Windows Phone 8.1 application.

image_thumb30

On the XAML MainPage insert the « PlayerFramework:MediaPlayer » and call it « Player ».

 <PlayerFramework:MediaPlayer x:Name="Player" Grid.Row="1" Grid.Column="2" Grid.RowSpan="4" Grid.ColumnSpan="1" Margin="20,10,20,10"         
            IsTimelineVisible="false" IsTimeElapsedVisible="false" IsDurationVisible="false" IsTimeRemainingVisible="false« 
            IsInfoVisible="false"  IsMoreVisible="false«  IsFastForwardVisible="False" IsRewindVisible="False"
            IsSkipBackVisible="False" IsSkipAheadVisible="False"  IsSkipPreviousVisible="False"   IsReplayVisible="False"  
            IsAudioSelectionVisible="False" IsCaptionSelectionVisible="False" HorizontalAlignment="Center"  VerticalAlignment="Center"  
            IsFullScreenVisible="True" Background="Black"  />

Create a method RegisterPlugins which associates the Adaptive plugin with the Smooth Streaming Uri opened by the Player, which creates a MediaProtectionManager associated with the Player and which registers the PlayReady events  « ServiceRequested » and « ComponentLoadFailed »

This method is called in the method OnNavigatedTo. 
Create a method RegisterDashPlugins which associates the DashDownloaderPlugin plugin with the Adaptive plugin used by the Player. This method is called before playing any MPEG DASH content.

 public Microsoft.PlayerFramework.Adaptive.AdaptivePlugin adaptivePlugin;
public Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin dashDownloaderPlugin;

void RegisterDashPlugin(bool bRegister)
{
    Microsoft.PlayerFramework.Adaptive.AdaptivePlugin plugin = Player.Plugins.OfType<Microsoft.PlayerFramework.Adaptive.AdaptivePlugin>().First();
    if (plugin != null)
    {
        if (bRegister == true)
        {
            LogMessage("Register DASH plugin");
            if (dashDownloaderPlugin == null)
                dashDownloaderPlugin = new Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin();
            plugin.DownloaderPlugin = dashDownloaderPlugin;
        }
        else
        {
            LogMessage("Unregister DASH plugin");
            plugin.DownloaderPlugin = null;
        }
    }
}
void RegisterPlugins()
{
    LogMessage("Register plugins");

    if (adaptivePlugin == null)
        adaptivePlugin = new Microsoft.PlayerFramework.Adaptive.AdaptivePlugin();

    Player.Plugins.Add(adaptivePlugin);

    // PlayReady
    // Init PlayReady Protection Manager
    var protectionManager = new MediaProtectionManager();
    Windows.Foundation.Collections.PropertySet cpSystems = new Windows.Foundation.Collections.PropertySet();
    cpSystems.Add("{F4637010-03C3-42CD-B932-B48ADF3A6A54}", "Microsoft.Media.PlayReadyClient.PlayReadyWinRTTrustedInput"); //Playready
    protectionManager.Properties.Add("Windows.Media.Protection.MediaProtectionSystemIdMapping", cpSystems);
    protectionManager.Properties.Add("Windows.Media.Protection.MediaProtectionSystemId", "{F4637010-03C3-42CD-B932-B48ADF3A6A54}");
    this.Player.ProtectionManager = protectionManager;
    
    // PlayReady Events registration
    Player.ProtectionManager.ComponentLoadFailed += ProtectionManager_ComponentLoadFailed;
    Player.ProtectionManager.ServiceRequested += ProtectionManager_ServiceRequested;
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    LogMessage("OnNavigatedTo");
    base.OnNavigatedTo(e);
    Application.Current.Suspending += App_Suspending;
    Application.Current.Resuming += App_Resuming;
    Player.MediaEnded += Player_MediaEnded;
    Player.MediaOpened += Player_MediaOpened;
    Player.MediaFailed += Player_MediaFailed;
#if WINDOWS_PHONE_APP
    DisplayInformation.GetForCurrentView().OrientationChanged += OnOrientationChanged;
#endif
    RegisterPlugins();
}

To support PlayReady the application must call the license server to acquire the PlayReady license associated with the content protected with PlayReady. You need to include in the project the file  CommonLicenseRequest.cs. This file implements the common class based on HttpClient to acquire the PlayReady license.

The method ProtectionManager_ServiceRequested is called each time the application requests a PlayReady license or an individualization. If it’s a individualization request, the method ReactiveIndivRequest is called. If it’s a license request, the methode LicenseAcquisitionRequest is called.    

If the URL used to acquire the PlayReady License is not forced and is the one defined in the PlayReady protection header, the method LicenseAcquisitionRequest calls licenseRequest.BeginServiceRequest. If the URL to acquire the PlayReady License is forced by the application, the method LicenseAcquisitionRequest creates a PlayReady challenge using the ChallengeCustomData and then call licenseAcquisition.AcquireLicense using the URL defined by the user. 

 private const int MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED = -2147174251;
private string PlayReadyLicenseUrl;
private string PlayReadyChallengeCustomData;

/// <summary>
/// Invoked when the Protection Manager can't load some components
/// </summary>
void ProtectionManager_ComponentLoadFailed(MediaProtectionManager sender, ComponentLoadFailedEventArgs e)
{
    LogMessage("ProtectionManager ComponentLoadFailed");
    e.Completion.Complete(false);
}
/// <summary>
/// Invoked to acquire the PlayReady License
/// </summary>
async void LicenseAcquisitionRequest(PlayReadyLicenseAcquisitionServiceRequest licenseRequest, MediaProtectionServiceCompletion CompletionNotifier, string Url, string ChallengeCustomData)
{
    bool bResult = false;
    string ExceptionMessage = string.Empty;

    try
    {
        if (!string.IsNullOrEmpty(Url))
        {
            LogMessage("ProtectionManager PlayReady Manual License Acquisition Service Request in progress - URL: " + Url);

            if (!string.IsNullOrEmpty(ChallengeCustomData))
            {
                System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
                byte[] b = encoding.GetBytes(ChallengeCustomData);
                licenseRequest.ChallengeCustomData = Convert.ToBase64String(b, 0, b.Length);
            }

            PlayReadySoapMessage soapMessage = licenseRequest.GenerateManualEnablingChallenge();

            byte[] messageBytes = soapMessage.GetMessageBody();
            HttpContent httpContent = new ByteArrayContent(messageBytes);

            IPropertySet propertySetHeaders = soapMessage.MessageHeaders;
            foreach (string strHeaderName in propertySetHeaders.Keys)
            {
                string strHeaderValue = propertySetHeaders[strHeaderName].ToString();

                // The Add method throws an ArgumentException try to set protected headers like "Content-Type"
                // so set it via "ContentType" property
                if (strHeaderName.Equals("Content-Type", StringComparison.OrdinalIgnoreCase))
                    httpContent.Headers.ContentType = MediaTypeHeaderValue.Parse(strHeaderValue);
                else
                    httpContent.Headers.Add(strHeaderName.ToString(), strHeaderValue);
            }
            CommonLicenseRequest licenseAcquision = new CommonLicenseRequest();
            HttpContent responseHttpContent = await licenseAcquision.AcquireLicense(new Uri(Url), httpContent);
            if (responseHttpContent != null)
            {
                Exception exResult = licenseRequest.ProcessManualEnablingResponse(await responseHttpContent.ReadAsByteArrayAsync());
                if (exResult != null)
                {
                    throw exResult;
                }
                bResult = true;
            }
            else
                ExceptionMessage = licenseAcquision.GetLastErrorMessage();
        }
        else
        {
            LogMessage("ProtectionManager PlayReady License Acquisition Service Request in progress - URL: " + licenseRequest.Uri.ToString());
            await licenseRequest.BeginServiceRequest();
            bResult = true;
        }
    }
    catch (Exception e)
    {
        ExceptionMessage = e.Message;
    }

    if (bResult == true)
        LogMessage(!string.IsNullOrEmpty(Url) ? "ProtectionManager Manual PlayReady License Acquisition Service Request successful" :
            "ProtectionManager PlayReady License Acquisition Service Request successful");
    else
        LogMessage(!string.IsNullOrEmpty(Url) ? "ProtectionManager Manual PlayReady License Acquisition Service Request failed: " + ExceptionMessage :
            "ProtectionManager PlayReady License Acquisition Service Request failed: " + ExceptionMessage);
    CompletionNotifier.Complete(bResult);
}
/// <summary>
/// Proactive Individualization Request 
/// </summary>
async void ProActiveIndivRequest()
{
    PlayReadyIndividualizationServiceRequest indivRequest = new PlayReadyIndividualizationServiceRequest();
    LogMessage("ProtectionManager PlayReady ProActive Individualization Service Request in progress...");
    bool bResultIndiv = await ReactiveIndivRequest(indivRequest, null);
    if (bResultIndiv == true)
        LogMessage("ProtectionManager PlayReady ProActive Individualization Service Request successful");
    else
        LogMessage("ProtectionManager PlayReady ProActive Individualization Service Request failed");

}
/// <summary>
/// Invoked to send the Individualization Request 
/// </summary>
async Task<bool> ReactiveIndivRequest(PlayReadyIndividualizationServiceRequest IndivRequest, MediaProtectionServiceCompletion CompletionNotifier)
{
    bool bResult = false;
    Exception exception = null;
    LogMessage("ProtectionManager PlayReady Individualization Service Request in progress...");
    try
    {
        await IndivRequest.BeginServiceRequest();
    }
    catch (Exception ex)
    {
        exception = ex;
    }
    finally
    {
        if (exception == null)
        {
            bResult = true;
        }
        else
        {
            COMException comException = exception as COMException;
            if (comException != null && comException.HResult == MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED)
            {
                IndivRequest.NextServiceRequest();
            }
        }
    }
    if (bResult == true)
        LogMessage("ProtectionManager PlayReady Individualization Service Request successful");
    else
        LogMessage("ProtectionManager PlayReady Individualization Service Request failed");
    if (CompletionNotifier != null) CompletionNotifier.Complete(bResult);
    return bResult;

}
/// <summary>
/// Invoked to send a PlayReady request (Individualization or License request)
/// </summary>
async void ProtectionManager_ServiceRequested(MediaProtectionManager sender, ServiceRequestedEventArgs srEvent)
{
    LogMessage("ProtectionManager ServiceRequested");
    if (srEvent.Request is PlayReadyIndividualizationServiceRequest)
    {
        PlayReadyIndividualizationServiceRequest IndivRequest = srEvent.Request as PlayReadyIndividualizationServiceRequest;
        bool bResultIndiv = await ReactiveIndivRequest(IndivRequest, srEvent.Completion);
    }
    else if (srEvent.Request is PlayReadyLicenseAcquisitionServiceRequest)
    {
        PlayReadyLicenseAcquisitionServiceRequest licenseRequest = srEvent.Request as PlayReadyLicenseAcquisitionServiceRequest;
        LicenseAcquisitionRequest(licenseRequest, srEvent.Completion, PlayReadyLicenseUrl, PlayReadyChallengeCustomData);
    }
}

In the method associated with Click event on button “Play”, first initialize PlayReadyLicenseUrl with the Uri of the PlayReady Server (if defined), initialize PlayReadyChallengeCustomData with the data required to generate the PlayReady challenge (if defined). Then call the method RegisterDashPlugin to register the DashDownloaderPlugin (if it’s MPEG DASH Uri), and then initialize Player Source with the Uri of the video you want to play.

 PlayReadyLicenseUrl = PlayReadyUri.Text;
PlayReadyChallengeCustomData = CustomData.Text;
RegisterDashPlugin((MediaUri.Text.EndsWith(".mpd", StringComparison.CurrentCultureIgnoreCase) || 
                     MediaUri.Text.EndsWith("manifest(format=mpd-time-csf)", StringComparison.CurrentCultureIgnoreCase)));
Player.Source = new Uri(MediaUri.Text);

Sample Uris compliant with MPEG DASH and Smooth Streaming protected with PlayReady format are available with the sample application.

 
https://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism/Manifest
https://wams.edgesuite.net/media/SintelTrailer_Smooth_from_WAME_CENC/NoSubSampleAdjustment/sintel_trailer-1080p.ism/manifest(format=mpd-time-csf)
https://wams.edgesuite.net/media/Tears_of_Steel_Smooth_1080p_Protected2/tears_of_steel_1080p.ism/manifest(format=mpd-time-csf)

By default the applications will try to play the following Smooth Streaming asset:

https://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism/Manifest

using the following URL for the license acquisition:

https://playready.directtaps.net/pr/svc/rightsmanager.asmx?PlayRight=1&UseSimpleNonPersistentLicense=1

This URL will return a non-persistent license. Each time the application will try to play the smooth streaming asset, a request to the PlayReady server will be transmitted.

By default, the challenge custom data is empty, you can change this field if the PlayReady server expect a specific challenge custom data.

If you use the following URL, the license returned will be persistent:

https://playready.directtaps.net/pr/svc/rightsmanager.asmx

Applications Windows Phone 8.0:

Add a reference to:

« Microsoft.Web.Media.SmoothStreaming », 
« Microsoft Player Framework »,

« Microsoft Player Framework Adaptive Streaming Plugin»,

« Microsoft Player Framework Dash Plugin» for Windows Phone 8.0 application.

image_thumb31              image_thumb33

Http Client Library: These PlayReady sample applications are based on Player Framework V2.0 and the PlayReady license acquisition is based on HttpClient class for both platforms Windows and Windows Phone.  
HttpClient is a part of .NET Framework 4.5 and Windows Store applications that provides developers an extremely easy way to connect with services across the Internet including REST-based services. HttpClient is available for Windows Phone developers provided you install the Microsoft HttpClient Libraries Nuget package.

On the XAML MainPage insert the « PlayerFramework:MediaPlayer » and call it « Player ».

 <PlayerFramework:MediaPlayer  Visibility="Visible" x:Name="Player"  Grid.Row="3" Grid.Column="0" 
Grid.ColumnSpan="3"  Grid.RowSpan="1"  Margin="10,10,10,10" Background="Black" Foreground="Black" 
IsAudioSelectionVisible="False" IsCaptionSelectionVisible="False"     HorizontalAlignment="Center"  VerticalAlignment="Center"  IsFullScreenVisible="False" />

Create a method RegisterPlugins which associates the Adaptive plugin with the Smooth Streaming Uri opened by the Player, which initialize the property “LicenseAcquirer” of Player MediaElement.

This method is called in the method OnNavigatedTo. 
Create a method RegisterDashPlugins which associates the DashDownloaderPlugin plugin with the Adaptive plugin used by the Player. This method is called before playing any MPEG DASH content.

 
public Microsoft.PlayerFramework.Adaptive.AdaptivePlugin adaptivePlugin;
public Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin dashDownloaderPlugin;

void RegisterDashPlugin(bool bRegister)
{
    Microsoft.PlayerFramework.Adaptive.AdaptivePlugin plugin = Player.Plugins.OfType<Microsoft.PlayerFramework.Adaptive.AdaptivePlugin>().First();
    if (plugin != null)
    {
        if (bRegister == true)
        {
            LogMessage("Register DASH plugin");
            if (dashDownloaderPlugin == null)
                dashDownloaderPlugin = new Microsoft.Media.AdaptiveStreaming.Dash.DashDownloaderPlugin();
            plugin.DownloaderPlugin = dashDownloaderPlugin;
        }
    }
}
void RegisterPlugins()
{
    LogMessage("Register plugins");
    if (adaptivePlugin == null)
        adaptivePlugin = new Microsoft.PlayerFramework.Adaptive.AdaptivePlugin();
    Player.Plugins.Add(adaptivePlugin);

    // PlayReady
    // Init PlayReady 
    adaptivePlugin.MediaElement.LicenseAcquirer = new WindowsPhoneLicenseAcquisition(null);
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
    LogMessage("OnNavigatedTo");
    base.OnNavigatedTo(e);
    PhoneApplicationService.Current.Deactivated += App_Suspending;
    PhoneApplicationService.Current.Activated += App_Resuming;
    Player.MediaEnded += Player_MediaEnded;
    Player.MediaOpened += Player_MediaOpened;
    Player.MediaFailed += Player_MediaFailed;
    RegisterPlugins();
}

To support PlayReady, the application must call the license server to acquire the PlayReady license associated with the content. You need to include in the project the files  CommonLicenseRequest.cs and WindowsPhoneLicenseAcquisition.cs . The file CommonLicenseRequest.cs implements the common class based on HttpClient to acquire the PlayReady license. The file WindowsPhoneLicenseAcquisition.cs implements the class WindowsPhoneLicenseAcquisition derived from the PlayReady class LicenseAcquirer used to acquire the PlayReady license.

In the method associated with the Click event on the « Play » button,

- initialize PlayReadyLicenseUrl with the PlayReady server Uri (if defined),

- initialize PlayReadyChallengeCustomData with the data required to generate the PlayReady challenge (if defined),

- initialize Player Source to null and

- call the Player method « Close » du Player

- if PlayReadyChallengeCustomData is defined, initialize LicenseAcquirer.ChallengeCustomData of Player Media Element.

- if PlayReadyLicenseUrl is defined, initialize LicenseAcquirer.LicenseServerUriOverride of Player Media Element .

- call the method RegisterDashPlugin

- then initialize the Player Source with the content Uri .

 PlayReadyLicenseUrl = PlayReadyUri.Text;
     PlayReadyChallengeCustomData = CustomData.Text;

     // Reset the source and close the player
     Player.Source = null;
     Player.Close();

     Microsoft.PlayerFramework.Adaptive.AdaptivePlugin ap = Player.Plugins.OfType<Microsoft.PlayerFramework.Adaptive.AdaptivePlugin>().FirstOrDefault();
     if (ap != null)
     {
         if (!string.IsNullOrEmpty(PlayReadyChallengeCustomData))
         {
             System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
             byte[] b = encoding.GetBytes(PlayReadyChallengeCustomData);
             ap.MediaElement.LicenseAcquirer.ChallengeCustomData = Convert.ToBase64String(b, 0, b.Length);
         }
         if (!string.IsNullOrEmpty(PlayReadyLicenseUrl))
             ap.MediaElement.LicenseAcquirer.LicenseServerUriOverride = new Uri(PlayReadyLicenseUrl, UriKind.Absolute);
         else
             ap.MediaElement.LicenseAcquirer.LicenseServerUriOverride = null;
     }
 
       Player.Visibility = System.Windows.Visibility.Visible;
       PlayerSSME.Visibility = System.Windows.Visibility.Collapsed;

     /// if MPEG DASH Uri Register Dash Plugin 
     RegisterDashPlugin((MediaUri.Text.EndsWith(".mpd", StringComparison.CurrentCultureIgnoreCase) || MediaUri.Text.EndsWith("manifest(format=mpd-time-csf)", StringComparison.CurrentCultureIgnoreCase)));

     Player.Source = new Uri(MediaUri.Text);
Player.Source = null;
Player.Close();

RegisterDashPlugin((MediaUri.Text.EndsWith(".mpd", StringComparison.CurrentCultureIgnoreCase) || 
                     MediaUri.Text.EndsWith("manifest(format=mpd-time-csf)", StringComparison.CurrentCultureIgnoreCase)));
Player.Source = new Uri(MediaUri.Text);

Sample Uris compliant with MPEG DASH and Smooth Streaming protected with PlayReady format are available with the sample application.

 
https://playready.directtaps.net/smoothstreaming/SSWSS720H264PR/SuperSpeedway_720.ism/Manifest
https://wams.edgesuite.net/media/SintelTrailer_Smooth_from_WAME_CENC/NoSubSampleAdjustment/sintel_trailer-1080p.ism/manifest(format=mpd-time-csf)
https://wams.edgesuite.net/media/Tears_of_Steel_Smooth_1080p_Protected2/tears_of_steel_1080p.ism/manifest(format=mpd-time-csf)

BUILDING THE APPLICATIONS

In order to build the MediaPlayer sample applications for Windows Phone 8.0, Windows Phone 8.1 and Windows 8.1, make sure you have the basics installed: a computer running Windows 8.1, Visual Studio 2013 Update 2 with Windows Phone 8.1 SDK and the supplementary SDKs:

DOWNLOADING THE PROJECTS

Download:                          C# (15.7 MB)  
Requires:                             Windows Phone 8, Windows 8.1, Windows Phone 8.1, Visual Studio 2013 Update 2  
Last updated:                       5/28/2014

License:                                MS-LPL

Technologies:                      PlayReady, WMV, MP4, MPEG2-TS, Smooth Streaming, MPEG DASH, 
                                             Player Framework, C#, XAML  
Topics:                                  PlayReady Smooth Streaming MPEG DASH Player for Windows Phone and Windows Store