Exportar (0) Imprimir
Expandir Tudo
Este tópico ainda não foi avaliado como - Avalie este tópico

Escutar notificações do Windows Azure Media Services

Atualizado: novembro de 2013

O Serviços de Mídia do Windows Azure possui a capacidade de fornecer mensagens de notificação para o armazenamento em fila do Windows Azure ao processar trabalhos de mídia. Este tópico mostra como obter essas mensagens de notificação do armazenamento em fila.

As mensagens entregues ao armazenamento em fila podem ser acessadas a partir de qualquer lugar do mundo. A arquitetura de mensagens em fila do Windows Azure é confiável e altamente escalonável. Pesquisar o armazenamento em fila é aconselhado em vez de outros métodos.

Um cenário comum para escutar as notificações do Media Services é se estiver desenvolvendo um sistema de gerenciamento de conteúdo que precise realizar algumas tarefas adicionais depois que o trabalho de codificações é concluído (por exemplo, acionar a próxima etapa em um fluxo de trabalho ou publicar conteúdo).

Considerações

Leve em consideração o seguinte ao desenvolver aplicativos Serviços de Mídia que utilizam a fila de armazenamento do Windows Azure.

Código de exemplo

O código de exemplo nesta seção faz o seguinte:

  1. Define a classe EncodingJobMessage que mapeia até o formato da mensagem de notificação. O código desserializa mensagens recebidas de filas dentro de objetos do tipo EncodingJobMessage.

  2. Carrega o Media Services e as informações de conta de armazenamento a partir do arquivo app.config. Utiliza essas informações para criar os objetos CloudMediaContext e CloudQueue.

  3. Cria a fila que receberá as mensagens de notificação sobre o trabalho de codificação.

  4. Cria o ponto de extremidade de notificação que é mapeado para a fila.

  5. Anexa a notificação do ponto de extremidade para o trabalho e envia o trabalho de codificação. É possível ter diversos pontos de extremidade de notificação anexos a um trabalho.

    Nesse exemplo, estamos interessados somente nos estados finais do processamento de trabalho, por isso passamos o NotificationJobState.FinalStatesOnly para o método AddNew.

    job.JobNotificationSubscriptions.AddNew(NotificationJobState.FinalStatesOnly, _notificationEndPoint);
    
    
    Ao passar o NotificationJobState.All, espere obter todas as notificações de alteração de estado: Na fila -> Agendado -> Em processo -> Concluído. Entretanto, conforme mencionado anteriormente, o serviço de armazenamento em filas do Azure não garante entrega ordenada. É possível usar a propriedade Timestamp (definida no tipo EncodingJobMessage no exemplo abaixo) para classificar mensagens. É possível obter mensagens de notificação duplicadas. Use a propriedade ETag (definida no tipo EncodingJobMessage) para verificar as duplicações. Observe que também é possível que algumas notificações de alteração de estado sejam puladas.

  6. Aguarda que o trabalho chegue ao estado Finished ao verificar a fila a cada 10 segundos. Exclui mensagens depois de serem processadas.

  7. Exclui a fila e o ponto de extremidade da notificação.

noteObservação
A maneira recomendada de monitorar o estado de um trabalho é ouvindo mensagens de notificação, conforme mostrado no exemplo a seguir.

Como alternativa, é possível verificar o estado de um trabalho usando a propriedade IJob.State.  Observe que uma mensagem de notificação sobre a conclusão de um trabalho pode chegar antes do State em IJob ser definido como Finished. A propriedade IJob.State  irá refletir o estado preciso com um  leve atraso.  

using System;
using System.Linq;
using System.Configuration;
using System.IO;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Generic;
using Microsoft.WindowsAzure.MediaServices.Client;
using System.Web;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Auth;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Runtime.Serialization.Json;

namespace JobNotification
{
    public class EncodingJobMessage
    {
        // MessageVersion is used for version control. 
        public String MessageVersion { get; set; }
    
        // Type of the event. Valid values are 
        // JobStateChange and NotificationEndpointRegistration.
        public String EventType { get; set; }
    
        // ETag is used to help the customer detect if 
        // the message is a duplicate of another message previously sent.
        public String ETag { get; set; }
    
        // Time of occurrence of the event.
        public String TimeStamp { get; set; }

        // Collection of values specific to the event.

        // For the JobStateChange event the values are:
        //     JobId - Id of the Job that triggered the notification.
        //     NewState- The new state of the Job. Valid values are:
        //          Scheduled, Processing, Canceling, Cancelled, Error, Finished
        //     OldState- The old state of the Job. Valid values are:
        //          Scheduled, Processing, Canceling, Cancelled, Error, Finished

        // For the NotificationEndpointRegistration event the values are:
        //     NotificationEndpointId- Id of the NotificationEndpoint 
        //          that triggered the notification.
        //     State- The state of the Endpoint. 
        //          Valid values are: Registered and Unregistered.

        public IDictionary<string, object> Properties { get; set; }
    }

    class Program
    {
        private static CloudMediaContext _context = null;
        private static CloudQueue _queue = null;
        private static INotificationEndPoint _notificationEndPoint = null;

        private static readonly string _singleInputMp4Path =
            Path.GetFullPath(@"C:\supportFiles\multifile\BigBuckBunny.mp4");

        static void Main(string[] args)
        {
            // Get the values from app.config file.
            string mediaServicesAccountName = ConfigurationManager.AppSettings["MediaServicesAccountName"];
            string mediaServicesAccountKey = ConfigurationManager.AppSettings["MediaServicesAccountKey"];
            string storageConnectionString = ConfigurationManager.AppSettings["StorageConnectionString"];


            string endPointAddress = Guid.NewGuid().ToString();

            // Create the context. 
            _context = new CloudMediaContext(mediaServicesAccountName, mediaServicesAccountKey);

            // Create the queue that will be receiving the notification messages.
            _queue = CreateQueue(storageConnectionString, endPointAddress);

            // Create the notification point that is mapped to the queue.
            _notificationEndPoint = 
                    _context.NotificationEndPoints.Create(
                    Guid.NewGuid().ToString(), NotificationEndPointType.AzureQueue, endPointAddress);


            if (_notificationEndPoint != null)
            {
                IJob job = SubmitEncodingJobWithNotificationEndPoint(_singleInputMp4Path);
                WaitForJobToReachedFinishedState(job.Id);
            }

            // Clean up.
            _queue.Delete();      
            _notificationEndPoint.Delete();
       }


        static public CloudQueue CreateQueue(string storageAccountConnectionString, string endPointAddress)
        {
            CloudStorageAccount storageAccount = CloudStorageAccount.Parse(storageAccountConnectionString);

            // Create the queue client
            CloudQueueClient queueClient = storageAccount.CreateCloudQueueClient();

            // Retrieve a reference to a queue
            CloudQueue queue = queueClient.GetQueueReference(endPointAddress);

            // Create the queue if it doesn't already exist
            queue.CreateIfNotExists();

            return queue;
        }
 

        // Upload a video file, and encode to Smooth Streaming format
        public static IJob SubmitEncodingJobWithNotificationEndPoint(string inputMediaFilePath)
        {
            // Declare a new job.
            IJob job = _context.Jobs.Create("My MP4 to Smooth Streaming encoding job");

            //Create an encrypted asset and upload the mp4. 
            IAsset asset = CreateAssetAndUploadSingleFile(AssetCreationOptions.StorageEncrypted, 
                inputMediaFilePath);

            // Get a media processor reference, and pass to it the name of the 
            // processor to use for the specific task.
            IMediaProcessor processor = GetLatestMediaProcessorByName("Windows Azure Media Encoder");

            // Create a task with the conversion details, using a configuration file. 
            ITask task = job.Tasks.AddNew("My Mp4 to Smooth Task",
                processor,
                "H264 Smooth Streaming 720p",
                Microsoft.WindowsAzure.MediaServices.Client.TaskOptions.None);

            // Specify the input asset to be encoded.
            task.InputAssets.Add(asset);

            // Add an output asset to contain the results of the job.
            task.OutputAssets.AddNew("Output asset",
                AssetCreationOptions.None);

            // Add a notification point to the job. You can add multiple notification points.  
            job.JobNotificationSubscriptions.AddNew(NotificationJobState.FinalStatesOnly, 
                _notificationEndPoint);

            job.Submit();

            return job;
        }

        public static void WaitForJobToReachedFinishedState(string jobId)
        {
            int expectedState = (int)JobState.Finished;
            int timeOutInSeconds = 600;

            bool jobReachedExpectedState = false;
            DateTime startTime = DateTime.Now;
            int jobState = -1;

            while (!jobReachedExpectedState)
            {
                // Specify how often you want to get messages from the queue.
                Thread.Sleep(TimeSpan.FromSeconds(10));

                foreach (var message in _queue.GetMessages(10))
                {
                    using (Stream stream = new MemoryStream(message.AsBytes))
                    {
                        DataContractJsonSerializerSettings settings = new DataContractJsonSerializerSettings();
                        settings.UseSimpleDictionaryFormat = true;
                        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(EncodingJobMessage), settings);
                        EncodingJobMessage encodingJobMsg = (EncodingJobMessage)ser.ReadObject(stream);

                        Console.WriteLine();

                        // Display the message information.
                        Console.WriteLine("EventType: {0}", encodingJobMsg.EventType);
                        Console.WriteLine("MessageVersion: {0}", encodingJobMsg.MessageVersion);
                        Console.WriteLine("ETag: {0}", encodingJobMsg.ETag);
                        Console.WriteLine("TimeStamp: {0}", encodingJobMsg.TimeStamp);
                        foreach (var property in encodingJobMsg.Properties)
                        {
                            Console.WriteLine("    {0}: {1}", property.Key, property.Value);
                        }

                        // We are only interested in messages 
                        // where EventType is "JobStateChange".
                        if (encodingJobMsg.EventType == "JobStateChange")
                        {
                            string JobId = (String)encodingJobMsg.Properties.Where(j => j.Key == "JobId").FirstOrDefault().Value;
                            if (JobId == jobId)
                            {
                                string oldJobStateStr = (String)encodingJobMsg.Properties.
                                                            Where(j => j.Key == "OldState").FirstOrDefault().Value;
                                string newJobStateStr = (String)encodingJobMsg.Properties.
                                                            Where(j => j.Key == "NewState").FirstOrDefault().Value;

                                JobState oldJobState = (JobState)Enum.Parse(typeof(JobState), oldJobStateStr);
                                JobState newJobState = (JobState)Enum.Parse(typeof(JobState), newJobStateStr);

                                if (newJobState == (JobState)expectedState)
                                {
                                    Console.WriteLine("job with Id: {0} reached expected state: {1}", 
                                        jobId, newJobState);
                                    jobReachedExpectedState = true;
                                    break;
                                }
                            }
                        }
                    }
                    // Delete the message after we've read it.
                    _queue.DeleteMessage(message);
                }

                // Wait until timeout
                TimeSpan timeDiff = DateTime.Now - startTime;
                bool timedOut = (timeDiff.TotalSeconds > timeOutInSeconds);
                if (timedOut)
                {
                    Console.WriteLine(@"Timeout for checking job notification messages, 
                                        latest found state ='{0}', wait time = {1} secs",
                        jobState,
                        timeDiff.TotalSeconds);

                    throw new TimeoutException();
                }
            }
        }
   
        static private IAsset CreateAssetAndUploadSingleFile(AssetCreationOptions assetCreationOptions, string singleFilePath)
        {
            var asset = _context.Assets.Create("UploadSingleFile_" + DateTime.UtcNow.ToString(), 
                assetCreationOptions);

            var fileName = Path.GetFileName(singleFilePath);

            var assetFile = asset.AssetFiles.Create(fileName);

            Console.WriteLine("Created assetFile {0}", assetFile.Name);
            Console.WriteLine("Upload {0}", assetFile.Name);

            assetFile.Upload(singleFilePath);
            Console.WriteLine("Done uploading of {0}", assetFile.Name);

            return asset;
        }

        static private IMediaProcessor GetLatestMediaProcessorByName(string mediaProcessorName)
        {
            var processor = _context.MediaProcessors.Where(p => p.Name == mediaProcessorName).
                ToList().OrderBy(p => new Version(p.Version)).LastOrDefault();

            if (processor == null)
                throw new ArgumentException(string.Format("Unknown media processor", mediaProcessorName));

            return processor;
        }
    }
}

O exemplo acima produziu o resultado a seguir. Os valores podem variar.

Created assetFile BigBuckBunny.mp4
Upload BigBuckBunny.mp4
Done uploading of BigBuckBunny.mp4

EventType: NotificationEndPointRegistration
MessageVersion: 1.0
ETag: e0238957a9b25bdf3351a88e57978d6a81a84527fad03bc23861dbe28ab293f6
TimeStamp: 2013-05-14T20:22:37
    NotificationEndPointId: nb:nepid:UUID:d6af9412-2488-45b2-ba1f-6e0ade6dbc27
    State: Registered
    Name: dde957b2-006e-41f2-9869-a978870ac620
    Created: 2013-05-14T20:22:35

EventType: JobStateChange
MessageVersion: 1.0
ETag: 4e381f37c2d844bde06ace650310284d6928b1e50101d82d1b56220cfcb6076c
TimeStamp: 2013-05-14T20:24:40
    JobId: nb:jid:UUID:526291de-f166-be47-b62a-11ffe6d4be54
    JobName: My MP4 to Smooth Streaming encoding job
    NewState: Finished
    OldState: Processing
    AccountName: westeuropewamsaccount
job with Id: nb:jid:UUID:526291de-f166-be47-b62a-11ffe6d4be54 reached expected 
State: Finished


Data da compilação:

2013-12-12
Isso foi útil para você?
(1500 caracteres restantes)
Agradecemos os seus comentários

Contribuições da comunidade

ADICIONAR
Mostrar:
© 2014 Microsoft. Todos os direitos reservados.