使用 Azure 媒体服务传送实时流Delivering Live Streaming with Azure Media Services

概述Overview

Azure 媒体服务提供了相应的 API 来向媒体服务发送启动操作请求(例如创建、启动、停止或删除频道)。Azure Media Services offers APIs that send requests to Media Services to start operations (for example: create, start, stop, or delete a channel). 这些操作是长时间运行的。These operations are long-running.

媒体服务 .NET SDK 提供了用来发送请求并等待操作完成的 API(在内部,这些 API 以特定的时间间隔轮询操作进度)。The Media Services .NET SDK provides APIs that send the request and wait for the operation to complete (internally, the APIs are polling for operation progress at some intervals). 例如,当调用 channel.Start() 时,该方法将在频道启动后返回。For example, when you call channel.Start(), the method returns after the channel is started. 还可以使用异步版本:await channel.StartAsync()(有关基于任务的异步模式的信息,请参阅 TAPYou can also use the asynchronous version: await channel.StartAsync() (for information about Task-based Asynchronous Pattern, see TAP). 发送操作请求并且在操作完成之前一直轮询操作状态的 API 称作“轮询方法”。APIs that send an operation request and then poll for the status until the operation is complete are called “polling methods”. 建议为富客户端应用程序和/或有状态服务使用这些方法(特别是异步版本)。These methods (especially the Async version) are recommended for rich client applications and/or stateful services.

某些情况下,应用程序不能等待长时运行的 http 请求并且希望手动轮询操作进度。There are scenarios where an application cannot wait for a long running http request and wants to poll for the operation progress manually. 一个典型的示例是与无状态 web 服务进行交互的浏览器:当浏览器请求创建频道时,web 服务会启动一个长时运行的操作并将操作 ID 返回到浏览器。A typical example would be a browser interacting with a stateless web service: when the browser requests to create a channel, the web service initiates a long running operation and returns the operation ID to the browser. 然后,浏览器可以根据该 ID 询问 Web 服务来获取操作状态。The browser could then ask the web service to get the operation status based on the ID. 媒体服务 .NET SDK 提供了非常适用于此情况的 API。The Media Services .NET SDK provides APIs that are useful for this scenario. 这些 API 称为“非轮询方法”。These APIs are called “non-polling methods”. “非轮询方法”有以下命名模式:Send“OperationName”Operation(例如,SendCreateOperation) 。The “non-polling methods” have the following naming pattern: SendOperationNameOperation (for example, SendCreateOperation). Send“OperationName” Operation 方法返回 IOperation 对象;返回的对象包含可以用来跟踪操作的信息。SendOperationNameOperation methods return the IOperation object; the returned object contains information that can be used to track the operation. Send“OperationName” OperationAsync 方法将返回“Task” The SendOperationNameOperationAsync methods return Task.

当前,以下类支持非轮询方法:Channel、StreamingEndpoint 和 Program 。Currently, the following classes support non-polling methods: Channel, StreamingEndpoint, and Program.

若要轮询操作状态,请对“OperationBaseCollection” 类使用“GetOperation” 方法。To poll for the operation status, use the GetOperation method on the OperationBaseCollection class. 使用以下时间间隔来检查操作状态:对于 ChannelStreamingEndpoint 操作,使用 30 秒;对于 Program 操作,使用 10 秒。Use the following intervals to check the operation status: for Channel and StreamingEndpoint operations, use 30 seconds; for Program operations, use 10 seconds.

创建和配置 Visual Studio 项目Create and configure a Visual Studio project

设置开发环境,并在 app.config 文件中填充连接信息,如使用 .NET 进行媒体服务开发中所述。Set up your development environment and populate the app.config file with connection information, as described in Media Services development with .NET.

示例Example

以下示例定义了一个名为 ChannelOperations的类。The following example defines a class called ChannelOperations. 可以将该类定义用作 Web 服务类定义的起点。This class definition could be a starting point for your web service class definition. 为简单起见,以下示例使用了方法的非异步版本。For simplicity, the following examples use the non-async versions of methods.

示例还展示了客户端可以如何使用该类。The example also shows how the client might use this class.

ChannelOperations 类定义ChannelOperations class definition

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

/// <summary> 
/// The ChannelOperations class only implements 
/// the Channel’s creation operation. 
/// </summary> 
public class ChannelOperations
{
    // Read values from the App.config file.
    private static readonly string _AADTenantDomain =
        ConfigurationManager.AppSettings["AMSAADTenantDomain"];
    private static readonly string _RESTAPIEndpoint =
        ConfigurationManager.AppSettings["AMSRESTAPIEndpoint"];
    private static readonly string _AMSClientId =
        ConfigurationManager.AppSettings["AMSClientId"];
    private static readonly string _AMSClientSecret =
        ConfigurationManager.AppSettings["AMSClientSecret"];

    // Field for service context.
    private static CloudMediaContext _context = null;

    public ChannelOperations()
    {
        AzureAdTokenCredentials tokenCredentials = 
            new AzureAdTokenCredentials(_AADTenantDomain,
                new AzureAdClientSymmetricKey(_AMSClientId, _AMSClientSecret),
                AzureEnvironments.AzureChinaCloudEnvironment);

        var tokenProvider = new AzureAdTokenProvider(tokenCredentials);

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

    /// <summary>  
    /// Initiates the creation of a new channel.  
    /// </summary>  
    /// <param name="channelName">Name to be given to the new channel</param>  
    /// <returns>  
    /// Operation Id for the long running operation being executed by Media Services. 
    /// Use this operation Id to poll for the channel creation status. 
    /// </returns> 
    public string StartChannelCreation(string channelName)
    {
        var operation = _context.Channels.SendCreateOperation(
            new ChannelCreationOptions
            {
                Name = channelName,
                Input = CreateChannelInput(),
                Preview = CreateChannelPreview(),
                Output = CreateChannelOutput()
            });

        return operation.Id;
    }

    /// <summary> 
    /// Checks if the operation has been completed. 
    /// If the operation succeeded, the created channel Id is returned in the out parameter.
    /// </summary> 
    /// <param name="operationId">The operation Id.</param> 
    /// <param name="channel">
    /// If the operation succeeded, 
    /// the created channel Id is returned in the out parameter.</param>
    /// <returns>Returns false if the operation is still in progress; otherwise, true.</returns> 
    public bool IsCompleted(string operationId, out string channelId)
    {
        IOperation operation = _context.Operations.GetOperation(operationId);
        bool completed = false;

        channelId = null;

        switch (operation.State)
        {
            case OperationState.Failed:
                // Handle the failure. 
                // For example, throw an exception. 
                // Use the following information in the exception: operationId, operation.ErrorMessage.
                break;
            case OperationState.Succeeded:
                completed = true;
                channelId = operation.TargetEntityId;
                break;
            case OperationState.InProgress:
                completed = false;
                break;
        }
        return completed;
    }

    private static ChannelInput CreateChannelInput()
    {
        return new ChannelInput
        {
            StreamingProtocol = StreamingProtocol.RTMP,
            AccessControl = new ChannelAccessControl
            {
                IPAllowList = new List<IPRange>
                    {
                        new IPRange
                        {
                            Name = "TestChannelInput001",
                            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",
                            Address = IPAddress.Parse("0.0.0.0"),
                            SubnetPrefixLength = 0
                        }
                    }
            }
        };
    }

    private static ChannelOutput CreateChannelOutput()
    {
        return new ChannelOutput
        {
            Hls = new ChannelOutputHls { FragmentsPerSegment = 1 }
        };
    }
}

客户端代码The client code

ChannelOperations channelOperations = new ChannelOperations();
string opId = channelOperations.StartChannelCreation("MyChannel001");

string channelId = null;
bool isCompleted = false;

while (isCompleted == false)
{
    System.Threading.Thread.Sleep(TimeSpan.FromSeconds(30));
    isCompleted = channelOperations.IsCompleted(opId, out channelId);
}

// If we got here, we should have the newly created channel id.
Console.WriteLine(channelId);

媒体服务学习路径Media Services learning paths

媒体服务 v3(最新版本)Media Services v3 (latest)

查看最新版本的 Azure 媒体服务!Check out the latest version of Azure Media Services!

媒体服务 v2(旧版)Media Services v2 (legacy)