Bagikan melalui


Streaming adaptif dengan PlayReady

Artikel ini menjelaskan cara menambahkan streaming adaptif konten multimedia dengan perlindungan konten Microsoft PlayReady ke aplikasi Platform Windows Universal (UWP).

Fitur ini saat ini mendukung pemutaran konten Streaming dinamis melalui HTTP (DASH).

HLS (Streaming Langsung HTTP Apple) tidak didukung dengan PlayReady.

Streaming lancar saat ini juga tidak didukung secara asli; Namun, PlayReady dapat diperluas dan dengan menggunakan kode atau pustaka tambahan, streaming Smooth yang dilindungi PlayReady dapat didukung, memanfaatkan perangkat lunak atau bahkan DRM perangkat keras (manajemen hak digital).

Artikel ini hanya berkaitan dengan aspek streaming adaptif khusus untuk PlayReady. Untuk informasi tentang menerapkan streaming adaptif secara umum, lihat Streaming adaptif.

Artikel ini menggunakan kode dari sampel streaming Adaptif di repositori Windows-universal-samples Microsoft di GitHub. Skenario 4 berkaitan dengan penggunaan streaming adaptif dengan PlayReady. Anda dapat mengunduh repositori dalam file ZIP dengan menavigasi ke tingkat akar repositori dan memilih tombol Unduh ZIP .

Anda akan memerlukan pernyataan penggunaan berikut:

using LicenseRequest;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using Windows.Foundation.Collections;
using Windows.Media.Protection;
using Windows.Media.Protection.PlayReady;
using Windows.Media.Streaming.Adaptive;
using Windows.UI.Xaml.Controls;

Namespace LicenseRequest berasal dari CommonLicenseRequest.cs, file PlayReady yang disediakan oleh Microsoft kepada penerima lisensi.

Anda perlu mendeklarasikan beberapa variabel global:

private AdaptiveMediaSource ams = null;
private MediaProtectionManager protectionManager = null;
private string playReadyLicenseUrl = "";
private string playReadyChallengeCustomData = "";

Anda juga ingin mendeklarasikan konstanta berikut:

private const uint MSPR_E_CONTENT_ENABLING_ACTION_REQUIRED = 0x8004B895;

Menyiapkan MediaProtectionManager

Untuk menambahkan perlindungan konten PlayReady ke aplikasi UWP, Anda harus menyiapkan objek MediaProtectionManager . Anda melakukan ini saat menginisialisasi objek AdaptiveMediaSource Anda.

Kode berikut menyiapkan MediaProtectionManager:

private void SetUpProtectionManager(ref MediaElement mediaElement)
{
    protectionManager = new MediaProtectionManager();

    protectionManager.ComponentLoadFailed += 
        new ComponentLoadFailedEventHandler(ProtectionManager_ComponentLoadFailed);

    protectionManager.ServiceRequested += 
        new ServiceRequestedEventHandler(ProtectionManager_ServiceRequested);

    PropertySet cpSystems = new PropertySet();

    cpSystems.Add(
        "{F4637010-03C3-42CD-B932-B48ADF3A6A54}", 
        "Windows.Media.Protection.PlayReady.PlayReadyWinRTTrustedInput");

    protectionManager.Properties.Add("Windows.Media.Protection.MediaProtectionSystemIdMapping", cpSystems);

    protectionManager.Properties.Add(
        "Windows.Media.Protection.MediaProtectionSystemId", 
        "{F4637010-03C3-42CD-B932-B48ADF3A6A54}");

    protectionManager.Properties.Add(
        "Windows.Media.Protection.MediaProtectionContainerGuid", 
        "{9A04F079-9840-4286-AB92-E65BE0885F95}");

    mediaElement.ProtectionManager = protectionManager;
}

Kode ini hanya dapat disalin ke aplikasi Anda, karena wajib untuk menyiapkan perlindungan konten.

Peristiwa ComponentLoadFailed diaktifkan saat beban data biner gagal. Kita perlu menambahkan penanganan aktivitas untuk menangani ini, menandakan bahwa beban tidak selesai:

private void ProtectionManager_ComponentLoadFailed(
    MediaProtectionManager sender, 
    ComponentLoadFailedEventArgs e)
{
    e.Completion.Complete(false);
}

Demikian pula, kita perlu menambahkan penanganan aktivitas untuk peristiwa ServiceRequested , yang diaktifkan saat layanan diminta. Kode ini memeriksa jenis permintaannya, dan merespons dengan tepat:

private async void ProtectionManager_ServiceRequested(
    MediaProtectionManager sender, 
    ServiceRequestedEventArgs e)
{
    if (e.Request is PlayReadyIndividualizationServiceRequest)
    {
        PlayReadyIndividualizationServiceRequest IndivRequest = 
            e.Request as PlayReadyIndividualizationServiceRequest;

        bool bResultIndiv = await ReactiveIndivRequest(IndivRequest, e.Completion);
    }
    else if (e.Request is PlayReadyLicenseAcquisitionServiceRequest)
    {
        PlayReadyLicenseAcquisitionServiceRequest licenseRequest = 
            e.Request as PlayReadyLicenseAcquisitionServiceRequest;

        LicenseAcquisitionRequest(
            licenseRequest, 
            e.Completion, 
            playReadyLicenseUrl, 
            playReadyChallengeCustomData);
    }
}

Permintaan layanan individualisasi

Kode berikut secara reaktif membuat permintaan layanan individualisasi PlayReady. Kami meneruskan permintaan sebagai parameter ke fungsi . Kami mengelilingi panggilan dalam blok try/catch, dan jika tidak ada pengecualian, kami mengatakan permintaan berhasil diselesaikan:

async Task<bool> ReactiveIndivRequest(
    PlayReadyIndividualizationServiceRequest IndivRequest, 
    MediaProtectionServiceCompletion CompletionNotifier)
{
    bool bResult = false;
    Exception exception = null;

    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 (CompletionNotifier != null) CompletionNotifier.Complete(bResult);
    return bResult;
}

Atau, kami mungkin ingin secara proaktif membuat permintaan layanan individualisasi, dalam hal ini kami memanggil fungsi berikut sebagai pengganti panggilan ReactiveIndivRequest kode di ProtectionManager_ServiceRequested:

async void ProActiveIndivRequest()
{
    PlayReadyIndividualizationServiceRequest indivRequest = new PlayReadyIndividualizationServiceRequest();
    bool bResultIndiv = await ReactiveIndivRequest(indivRequest, null);
}

Permintaan layanan akuisisi lisensi

Jika sebaliknya permintaannya adalah PlayReadyLicenseAcquisitionServiceRequest, kami memanggil fungsi berikut untuk meminta dan memperoleh lisensi PlayReady. Kami memberi tahu objek MediaProtectionServiceCompletion bahwa kami meneruskan apakah permintaan berhasil atau tidak, dan kami menyelesaikan permintaan:

async void LicenseAcquisitionRequest(
    PlayReadyLicenseAcquisitionServiceRequest licenseRequest, 
    MediaProtectionServiceCompletion CompletionNotifier, 
    string Url, 
    string ChallengeCustomData)
{
    bool bResult = false;
    string ExceptionMessage = string.Empty;

    try
    {
        if (!string.IsNullOrEmpty(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();

                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
        {
            await licenseRequest.BeginServiceRequest();
            bResult = true;
        }
    }
    catch (Exception e)
    {
        ExceptionMessage = e.Message;
    }

    CompletionNotifier.Complete(bResult);
}

Menginisialisasi AdaptiveMediaSource

Terakhir, Anda akan memerlukan fungsi untuk menginisialisasi AdaptiveMediaSource, yang dibuat dari Uri dan MediaElement tertentu. Uri harus menjadi tautan ke file media (HLS atau DASH); MediaElement harus ditentukan dalam XAML Anda.

async private void InitializeAdaptiveMediaSource(System.Uri uri, MediaElement m)
{
    AdaptiveMediaSourceCreationResult result = await AdaptiveMediaSource.CreateFromUriAsync(uri);
    if (result.Status == AdaptiveMediaSourceCreationStatus.Success)
    {
        ams = result.MediaSource;
        SetUpProtectionManager(ref m);
        m.SetMediaStreamSource(ams);
    }
    else
    {
        // Error handling
    }
}

Anda dapat memanggil fungsi ini di mana pun peristiwa menangani awal streaming adaptif; misalnya, dalam peristiwa klik tombol.

Lihat juga