Come eseguire lo streaming live con codificatori locali mediante .NET

Questa esercitazione illustra come usare l'SDK di Servizi multimediali di Azure per .NET per creare un canale configurato per la distribuzione pass-through.

Prerequisiti

Per completare l'esercitazione è necessario quanto segue:

È consigliabile esaminare i seguenti articoli:

Creare e configurare un progetto di Visual Studio

Configurare l'ambiente di sviluppo e popolare il file app.config con le informazioni di connessione, come descritto in Sviluppo di applicazioni di Servizi multimediali con .NET.

Esempio

Il seguente esempio di codice illustra come ottenere le attività seguenti:

  • Connettersi a Servizi multimediali
  • Creare un canale
  • Aggiornare il canale
  • Recuperare l'endpoint di input del canale. È necessario fornire l'endpoint di input al codificatore live locale. Il codificatore live converte i segnali dalla fotocamera ai flussi che vengono inviati all'endpoint di input del canale (inserimento).
  • Recuperare l'endpoint di anteprima del canale
  • Creare e avviare un programma
  • Creare un localizzatore necessario per accedere al programma
  • Creare e avviare uno StreamingEndpoint
  • Aggiornare l'endpoint di streaming
  • Arresto delle risorse
Importante

Verificare che l'endpoint di streaming da cui si vuole trasmettere il contenuto sia nello stato In esecuzione.

Nota

È previsto un limite di 1.000.000 di criteri per i diversi criteri AMS (ad esempio per i criteri Locator o ContentKeyAuthorizationPolicy). Usare lo stesso ID criterio se si usano sempre gli stessi giorni/autorizzazioni di accesso, come nel cado di criteri per i localizzatori che devono rimanere attivi per molto tempo (criteri di non caricamento). Per altre informazioni, vedere questo argomento.

Per informazioni su come configurare un codificatore live, vedere Codificatori live e supporto RTMP di Servizi multimediali di Azure.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using Microsoft.WindowsAzure.MediaServices.Client;

namespace AMSLiveTest
{
    class Program
    {
    private const string StreamingEndpointName = "streamingendpoint001";
    private const string ChannelName = "channel001";
    private const string AssetlName = "asset001";
    private const string ProgramlName = "program001";

    // Read values from the App.config file.
    private static readonly string _AADTenantDomain =
    ConfigurationManager.AppSettings["AADTenantDomain"];
    private static readonly string _RESTAPIEndpoint =
    ConfigurationManager.AppSettings["MediaServiceRESTAPIEndpoint"];

    private static CloudMediaContext _context = null;

    static void Main(string[] args)
    {
        var tokenCredentials = new AzureAdTokenCredentials(_AADTenantDomain, AzureEnvironments.AzureCloudEnvironment);
        var tokenProvider = new AzureAdTokenProvider(tokenCredentials);

        _context = new CloudMediaContext(new Uri(_RESTAPIEndpoint), tokenProvider);

        IChannel channel = CreateAndStartChannel();

        // Set the Live Encoder to point to the channel's input endpoint:
        string ingestUrl = channel.Input.Endpoints.FirstOrDefault().Url.ToString();

        // Use the previewEndpoint to preview and verify
        // that the input from the encoder is actually reaching the Channel.
        string previewEndpoint = channel.Preview.Endpoints.FirstOrDefault().Url.ToString();

        IProgram program = CreateAndStartProgram(channel);
        ILocator locator = CreateLocatorForAsset(program.Asset, program.ArchiveWindowLength);
        IStreamingEndpoint streamingEndpoint = CreateAndStartStreamingEndpoint(false);

        // Once you are done streaming, clean up your resources.
        Cleanup(streamingEndpoint, channel);
    }

    public static IChannel CreateAndStartChannel()
    {
        //If you want to change the Smooth fragments to HLS segment ratio, you would set the ChannelCreationOptions’s Output property.

        IChannel channel = _context.Channels.Create(
        new ChannelCreationOptions
        {
        Name = ChannelName,
        Input = CreateChannelInput(),
        Preview = CreateChannelPreview()
        });

        //Starting and stopping Channels can take some time to execute. To determine the state of operations after calling Start or Stop, query the IChannel.State .

        channel.Start();

        return channel;
    }

    private static ChannelInput CreateChannelInput()
    {
        return new ChannelInput
        {
        StreamingProtocol = StreamingProtocol.RTMP,
        AccessControl = new ChannelAccessControl
        {
            IPAllowList = new List<IPRange>
                {
                new IPRange
                {
                Name = "TestChannelInput001",
                // Setting 0.0.0.0 for Address and 0 for SubnetPrefixLength
                // will allow access to IP addresses.
                Address = IPAddress.Parse("0.0.0.0"),
                SubnetPrefixLength = 0
                }
            }
        }
        };
    }

    private static ChannelPreview CreateChannelPreview()
    {
        return new ChannelPreview
        {
        AccessControl = new ChannelAccessControl
        {
            IPAllowList = new List<IPRange>
            {
                new IPRange
                {
                Name = "TestChannelPreview001",
                // Setting 0.0.0.0 for Address and 0 for SubnetPrefixLength
                // will allow access to IP addresses.
                Address = IPAddress.Parse("0.0.0.0"),
                SubnetPrefixLength = 0
                }
            }
        }
        };
    }

    public static void UpdateCrossSiteAccessPoliciesForChannel(IChannel channel)
    {
        var clientPolicy =
        @"<?xml version=""1.0"" encoding=""utf-8""?>
        <access-policy>
            <cross-domain-access>
            <policy>
                <allow-from http-request-headers=""*"" http-methods=""*"">
                <domain uri=""*""/>
                </allow-from>
                <grant-to>
                   <resource path=""/"" include-subpaths=""true""/>
                </grant-to>
            </policy>
            </cross-domain-access>
        </access-policy>";

        var xdomainPolicy =
        @"<?xml version=""1.0"" ?>
        <cross-domain-policy>
            <allow-access-from domain=""*"" />
        </cross-domain-policy>";

        channel.CrossSiteAccessPolicies.ClientAccessPolicy = clientPolicy;
        channel.CrossSiteAccessPolicies.CrossDomainPolicy = xdomainPolicy;

        channel.Update();
    }

    public static IProgram CreateAndStartProgram(IChannel channel)
    {
        IAsset asset = _context.Assets.Create(AssetlName, AssetCreationOptions.None);

        // Create a Program on the Channel. You can have multiple Programs that overlap or are sequential;
        // however each Program must have a unique name within your Media Services account.
        IProgram program = channel.Programs.Create(ProgramlName, TimeSpan.FromHours(3), asset.Id);
        program.Start();

        return program;
    }

    public static ILocator CreateLocatorForAsset(IAsset asset, TimeSpan ArchiveWindowLength)
    {
        // You cannot create a streaming locator using an AccessPolicy that includes write or delete permissions.            

        var locator = _context.Locators.CreateLocator
        (
            LocatorType.OnDemandOrigin,
            asset,
            _context.AccessPolicies.Create
            (
            "Live Stream Policy",
            ArchiveWindowLength,
            AccessPermissions.Read
            )
        );

        return locator;
    }

    public static IStreamingEndpoint CreateAndStartStreamingEndpoint(bool createNew)
    {
        IStreamingEndpoint streamingEndpoint = null;
        if (createNew)
        {
        var options = new StreamingEndpointCreationOptions
        {
            Name = StreamingEndpointName,
            ScaleUnits = 1,
            AccessControl = GetAccessControl(),
            CacheControl = GetCacheControl()
        };

        streamingEndpoint = _context.StreamingEndpoints.Create(options);
        }
        else
        {
        streamingEndpoint = _context.StreamingEndpoints.FirstOrDefault();
        }


        if (streamingEndpoint.State == StreamingEndpointState.Stopped)
        streamingEndpoint.Start();

        return streamingEndpoint;
    }

    private static StreamingEndpointAccessControl GetAccessControl()
    {
        return new StreamingEndpointAccessControl
        {
        IPAllowList = new List<IPRange>
            {
            new IPRange
            {
                Name = "Allow all",
                Address = IPAddress.Parse("0.0.0.0"),
                SubnetPrefixLength = 0
            }
            },

        AkamaiSignatureHeaderAuthenticationKeyList = new List<AkamaiSignatureHeaderAuthenticationKey>
            {
            new AkamaiSignatureHeaderAuthenticationKey
            {
                Identifier = "My key",
                Expiration = DateTime.UtcNow + TimeSpan.FromDays(365),
                Base64Key = Convert.ToBase64String(GenerateRandomBytes(16))
            }
            }
        };
    }

    private static byte[] GenerateRandomBytes(int length)
    {
        var bytes = new byte[length];
        using (var rng = new RNGCryptoServiceProvider())
        {
        rng.GetBytes(bytes);
        }

        return bytes;
    }

    private static StreamingEndpointCacheControl GetCacheControl()
    {
        return new StreamingEndpointCacheControl
        {
        MaxAge = TimeSpan.FromSeconds(1000)
        };
    }

    public static void UpdateCrossSiteAccessPoliciesForStreamingEndpoint(IStreamingEndpoint streamingEndpoint)
    {
        var clientPolicy =
        @"<?xml version=""1.0"" encoding=""utf-8""?>
        <access-policy>
            <cross-domain-access>
            <policy>
                <allow-from http-request-headers=""*"" http-methods=""*"">
                <domain uri=""*""/>
                </allow-from>
                <grant-to>
                   <resource path=""/"" include-subpaths=""true""/>
                </grant-to>
            </policy>
            </cross-domain-access>
        </access-policy>";

        var xdomainPolicy =
        @"<?xml version=""1.0"" ?>
        <cross-domain-policy>
            <allow-access-from domain=""*"" />
        </cross-domain-policy>";

        streamingEndpoint.CrossSiteAccessPolicies.ClientAccessPolicy = clientPolicy;
        streamingEndpoint.CrossSiteAccessPolicies.CrossDomainPolicy = xdomainPolicy;

        streamingEndpoint.Update();
    }

    public static void Cleanup(IStreamingEndpoint streamingEndpoint,
                    IChannel channel)
    {
        if (streamingEndpoint != null)
        {
        streamingEndpoint.Stop();
        if(streamingEndpoint.Name != "default")
            streamingEndpoint.Delete();
        }

        IAsset asset;
        if (channel != null)
        {

        foreach (var program in channel.Programs)
        {
            asset = _context.Assets.Where(se => se.Id == program.AssetId)
                        .FirstOrDefault();

            program.Stop();
            program.Delete();

            if (asset != null)
            {
            foreach (var l in asset.Locators)
                l.Delete();

            asset.Delete();
            }
        }

        channel.Stop();
        channel.Delete();
        }
    }
    }
}

Passaggio successivo

Analizzare i percorsi di apprendimento dei Servizi multimediali

I percorsi di apprendimento di Servizi multimediali di Azure sono disponibili qui:

Fornire commenti e suggerimenti

Usare il forum di suggerimenti degli utenti per fornire commenti e suggerimenti su come migliorare Servizi multimediali di Azure. È anche possibile passare direttamente a una delle categorie seguenti: