CINXE.COM
Stream live with Media Services by using .NET 7.0 | Microsoft Learn
<!DOCTYPE html><html class="hasSidebar hasPageActions hasBreadcrumb conceptual has-default-focus theme-light" lang="en-us" dir="ltr" data-authenticated="false" data-auth-status-determined="false" data-target="docs" x-ms-format-detection="none"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta property="og:title" content="Stream live with Media Services by using .NET 7.0" /> <meta property="og:type" content="website" /> <meta property="og:url" content="https://learn.microsoft.com/en-us/azure/media-services/latest/stream-live-tutorial-with-api" /><meta property="og:description" content="In Azure Media Services, live events are responsible for processing live streaming content. A live event provides an input endpoint (ingest URL) that you then provide to a live encoder. The live event receives input streams from the live encoder and makes them available for streaming through one or more streaming endpoints. Live events also provide a preview endpoint (preview URL) that you use to preview and validate your stream before further processing and delivery." /><meta property="og:image" content="https://learn.microsoft.com/en-us/media/open-graph-image.png" /> <meta property="og:image:alt" content="Microsoft Learn" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:site" content="@MicrosoftLearn" /> <meta name="color-scheme" content="light dark"><meta name="author" content="IngridAtMicrosoft" /> <meta name="breadcrumb_path" content="/azure/media-services/breadcrumb/toc.json" /> <meta name="depot_name" content="MSDN.azure-media-services" /> <meta name="description" content="In Azure Media Services, live events are responsible for processing live streaming content. A live event provides an input endpoint (ingest URL) that you then provide to a live encoder. The live event receives input streams from the live encoder and makes them available for streaming through one or more streaming endpoints. Live events also provide a preview endpoint (preview URL) that you use to preview and validate your stream before further processing and delivery." /> <meta name="document_id" content="e9bf83ff-20b4-eee4-3f59-d5a452d637f4" /> <meta name="document_version_independent_id" content="e9bf83ff-20b4-eee4-3f59-d5a452d637f4" /> <meta name="feedback_help_link_type" content="" /> <meta name="feedback_help_link_url" content="" /> <meta name="feedback_product_url" content="" /> <meta name="feedback_system" content="None" /> <meta name="git_commit_id" content="e576c650f94b508fcdf1bf0420f190f504dfa725" /> <meta name="gitcommit" content="https://github.com/MicrosoftDocs/azure-media-services-pr/blob/e576c650f94b508fcdf1bf0420f190f504dfa725/media-services/latest/stream-live-tutorial-with-api.md" /> <meta name="locale" content="en-us" /> <meta name="ms.author" content="inhenkel" /> <meta name="ms.date" content="07/17/2023" /> <meta name="ms.service" content="azure-media-services" /> <meta name="ms.topic" content="tutorial" /> <meta name="original_content_git_url" content="https://github.com/MicrosoftDocs/azure-media-services-pr/blob/live/media-services/latest/stream-live-tutorial-with-api.md" /> <meta name="page_type" content="conceptual" /> <meta name="pdf_url_template" content="https://learn.microsoft.com/pdfstore/en-us/MSDN.azure-media-services/{branchName}{pdfName}" /> <meta name="schema" content="Conceptual" /> <meta name="site_name" content="Docs" /> <meta name="toc_rel" content="toc.json" /> <meta name="updated_at" content="2024-10-23 03:11 PM" /> <meta name="word_count" content="2792" /> <meta name="persistent_id" content="92f989f7-1c9e-24b2-7994-8cce2f9598bf" /> <meta name="cmProducts" content="https://authoring-docs-microsoft.poolparty.biz/devrel/2d774b87-7dcb-40bf-a0b9-5a7a9efff0d1" data-source="generated" /> <meta name="spProducts" content="https://authoring-docs-microsoft.poolparty.biz/devrel/89dc5f37-0e4e-4b05-ad87-5fcd2b941a8a" data-source="generated" /> <meta name="github_feedback_content_git_url" content="https://github.com/MicrosoftDocs/azure-media-services/blob/main/media-services/latest/stream-live-tutorial-with-api.md" /><link href="https://learn.microsoft.com/en-us/azure/media-services/latest/stream-live-tutorial-with-api" rel="canonical"><title>Stream live with Media Services by using .NET 7.0 | Microsoft Learn</title><link rel="stylesheet" href="/static/assets/0.4.028726178/styles/site-ltr.css"> <script id="msdocs-script"> var msDocs = {environment: { supportLevel: 'production', accessLevel: 'online', reviewFeatures: false, systemContent: true, azurePortalHostname: 'portal.azure.com', legacyHosting: false, siteName: 'learn', },data: { timeOrigin: Date.now(), contentLocale: 'en-us', contentDir: 'ltr', userLocale: 'en-us', userDir: 'ltr', pageTemplate: 'Conceptual', brand: '', context: {}, hasBinaryRating: true, feedbackHelpLinkType:'', feedbackHelpLinkUrl:'', standardFeedback: false, showFeedbackReport: false, enableTutorialFeedback: false, feedbackSystem: 'None', feedbackGitHubRepo: '', feedbackProductUrl: '',extendBreadcrumb: true,isEditDisplayable: false, hideViewSource: false, hasPageActions: true, hasPrintButton: true, hasBookmark: true, hasShare: true, isPermissioned: false, isPrivateUnauthorized: false,hasRecommendations: true,contributors: [{ name: "IngridAtMicrosoft", url: "https://github.com/IngridAtMicrosoft" }],}, functions:{} }; </script><script src="https://wcpstatic.microsoft.com/mscc/lib/v2/wcp-consent.js"></script> <script src="https://js.monitor.azure.com/scripts/c/ms.jsll-4.min.js"></script><script src="/static/assets/0.4.028726178/global/deprecation.js"></script><script src="/static/assets/0.4.028726178/scripts/en-us/index-docs.js"></script></head> <body lang="en-us" dir="ltr"> <div class="header-holder has-default-focus"> <a href="#main" style="z-index: 1070" class="outline-color-text visually-hidden-until-focused position-fixed inner-focus focus-visible top-0 left-0 right-0 padding-xs text-align-center has-body-background" tabindex="1">Skip to main content</a><div hidden id="cookie-consent-holder" data-test-id="cookie-consent-container"></div> <div id="unsupported-browser" style=" background-color: white; color: black; padding: 16px; border-bottom: 1px solid grey;" hidden > <div style="max-width: 800px; margin: 0 auto;"> <p style="font-size: 24px">This browser is no longer supported.</p> <p style="font-size: 16px; margin-top: 16px;">Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.</p> <div style="margin-top: 12px;"> <a href="https://go.microsoft.com/fwlink/p/?LinkID=2092881 " style=" background-color: #0078d4; border: 1px solid #0078d4; color: white; padding: 6px 12px; border-radius: 2px; display: inline-block; ">Download Microsoft Edge</a> <a href="https://learn.microsoft.com/en-us/lifecycle/faq/internet-explorer-microsoft-edge" style=" background-color: white; padding: 6px 12px; border: 1px solid #505050; color: #171717; border-radius: 2px; display: inline-block; ">More info about Internet Explorer and Microsoft Edge</a> </div> </div> </div> <!-- liquid-tag banners global --> <!-- site header --> <header id="ms--site-header" data-test-id="site-header-wrapper" role="banner" itemscope="itemscope" itemtype="http://schema.org/Organization"> <div id="ms--mobile-nav" class="site-header display-none-tablet padding-inline-none gap-none" data-bi-name="mobile-header" data-test-id="mobile-header"></div> <div id="ms--primary-nav" class="site-header display-none display-flex-tablet" data-bi-name="L1-header" data-test-id="primary-header"></div> <div id="ms--secondary-nav" class="display-none" data-bi-name="L2-header" data-test-id="secondary-header"></div> </header><div id="content-header" class="content-header uhf-container has-padding has-default-focus border-bottom-none" data-bi-name="content-header"> <div class="content-header-controls margin-xxs margin-inline-sm-tablet"> <button type="button" class="contents-button button button-sm margin-right-xxs" data-bi-name="contents-expand" aria-haspopup="true" data-contents-button> <span class="icon"><span class="docon docon-menu" aria-hidden="true"></span></span> <span class="contents-expand-title">Table of contents</span> </button> <button type="button" class="ap-collapse-behavior ap-expanded button button-sm" data-bi-name="ap-collapse" aria-controls="action-panel"> <span class="icon"><span class="docon docon-exit-mode" aria-hidden="true"></span></span> <span>Exit focus mode</span> </button> </div> </div><div id="disclaimer-holder" class="has-overflow-hidden has-default-focus"> <!-- liquid-tag banners sectional --> </div> </div> <div class="mainContainer uhf-container has-default-focus" data-bi-name="body"> <div class="columns has-large-gaps is-gapless-mobile "><div id="left-container" class="left-container is-hidden-mobile column is-one-third-tablet is-one-quarter-desktop"> <nav id="affixed-left-container" class="margin-top-sm-tablet position-sticky display-flex flex-direction-column" aria-label="Primary"></nav> </div><!-- .primary-holder --> <section class="primary-holder column is-two-thirds-tablet is-three-quarters-desktop"> <!--div.columns --> <div class="columns is-gapless-mobile has-large-gaps "><div id="main-column" class="column is-full is-8-desktop"> <main id="main" class="" role="main" data-bi-name="content" lang="en-us" dir="ltr"><!-- article-header --> <div id="article-header" class="background-color-body margin-top-sm-tablet margin-bottom-xs display-none-print"> <div class="display-flex align-items-center "><details id="article-header-breadcrumbs-overflow-popover" class="popover" data-for="article-header-breadcrumbs"> <summary class="button button-clear button-primary button-sm inner-focus" aria-label="All breadcrumbs"> <span class="icon"> <span class="docon docon-more"></span> </span> </summary> <div id="article-header-breadcrumbs-overflow" class="popover-content padding-none"> </div> </details> <bread-crumbs id="article-header-breadcrumbs" data-test-id="article-header-breadcrumbs" class="overflow-hidden flex-grow-1 margin-right-sm margin-right-md-tablet margin-right-lg-desktop margin-left-negative-xxs padding-left-xxs"></bread-crumbs><div id="article-header-page-actions" class="opacity-none margin-left-auto display-flex flex-wrap-no-wrap align-items-stretch"><a id="lang-link-tablet" class="button button-primary button-clear button-sm display-none display-inline-flex-tablet" title="Read in English" data-bi-name="language-toggle" data-read-in-link hidden> <span class="icon margin-none" aria-hidden="true" data-read-in-link-icon> <span class="docon docon-locale-globe"></span> </span> <span class="is-visually-hidden" data-read-in-link-text>Read in English</span> </a><button type="button" class="collection button button-clear button-sm button-primary display-none display-inline-flex-tablet" data-list-type="collection" data-bi-name="collection" title="Add to collection"> <span class="icon margin-none" aria-hidden="true"> <span class="docon docon-circle-addition"></span> </span> <span class="collection-status is-visually-hidden">Save</span> </button><a data-contenteditbtn class="button button-clear button-sm text-decoration-none button-primary display-none display-inline-flex-tablet" aria-label="Edit" title="Edit This Document" data-bi-name="edit" hidden href="https://github.com/MicrosoftDocs/azure-media-services/blob/main/media-services/latest/stream-live-tutorial-with-api.md" data-original_content_git_url="https://github.com/MicrosoftDocs/azure-media-services-pr/blob/live/media-services/latest/stream-live-tutorial-with-api.md" data-original_content_git_url_template="{repo}/blob/{branch}/media-services/latest/stream-live-tutorial-with-api.md" data-pr_repo="" data-pr_branch=""> <span class="icon margin-none" aria-hidden="true"> <span class="docon docon-edit-outline"></span> </span> </a> <details class="popover popover-right" id="article-header-page-actions-overflow"> <summary class="justify-content-flex-start button button-clear button-sm button-primary" aria-label="More actions" title="More actions"> <span class="icon" aria-hidden="true"> <span class="docon docon-more-vertical"></span> </span> </summary> <div class="popover-content padding-xs"><button data-page-action-item="overflow-mobile" type="button" class="justify-content-flex-start button-block button-sm has-inner-focus button button-clear display-none-tablet" data-bi-name="contents-expand" data-contents-button data-popover-close> <span class="icon"> <span class="docon docon-editor-list-bullet" aria-hidden="true"></span> </span><span class="contents-expand-title">Table of contents</span></button><a id="lang-link-overflow" class="justify-content-flex-start button-sm has-inner-focus button button-clear button-block display-none-tablet" title="Read in English" data-bi-name="language-toggle" data-page-action-item="overflow-mobile" data-check-hidden="true" data-read-in-link hidden > <span class="icon" aria-hidden="true" data-read-in-link-icon> <span class="docon docon-locale-globe"></span> </span> <span data-read-in-link-text>Read in English</span> </a><button type="button" class="collection justify-content-flex-start button button-clear button-sm has-inner-focus button-block display-none-tablet" data-list-type="collection" data-bi-name="collection" title="Save" data-page-action-item="overflow-mobile" data-check-hidden="true" data-popover-close> <span class="icon" aria-hidden="true"> <span class="docon docon-circle-addition"></span> </span> <span class="collection-status">Save</span> </button> <button type="button" class="collection justify-content-flex-start button button-clear button-sm has-inner-focus button-block display-none-tablet" data-list-type="plan" data-bi-name="plan" title="Add to Plan" data-page-action-item="overflow-mobile" data-check-hidden="true" data-popover-close hidden> <span class="icon" aria-hidden="true"> <span class="docon docon-circle-addition"></span> </span> <span class="plan-status">Add to Plan</span> </button><a data-contenteditbtn class="button button-clear button-block button-sm has-inner-focus justify-content-flex-start text-decoration-none display-none-tablet" aria-label="Edit" title="Edit This Document" data-bi-name="edit" hidden href="https://github.com/MicrosoftDocs/azure-media-services/blob/main/media-services/latest/stream-live-tutorial-with-api.md" data-original_content_git_url="https://github.com/MicrosoftDocs/azure-media-services-pr/blob/live/media-services/latest/stream-live-tutorial-with-api.md" data-original_content_git_url_template="{repo}/blob/{branch}/media-services/latest/stream-live-tutorial-with-api.md" data-pr_repo="" data-pr_branch=""> <span class="icon" aria-hidden="true"> <span class="docon docon-edit-outline"></span> </span> <span>Edit</span> </a><div aria-hidden="true" class="margin-none" data-page-action-item="overflow-all"></div> <hr class="display-none-tablet margin-bottom-xxs margin-top-xxs" /> <h4 class="font-size-sm padding-left-xxs">Share via</h4> <a class="button button-clear button-sm button-block has-inner-focus text-decoration-none justify-content-flex-start share-facebook" data-bi-name="facebook" data-page-action-item="overflow-all"> <span class="icon" aria-hidden="true"> <span class="docon docon-facebook-share font-size-md color-primary"></span> </span> <span class="margin-left-xxs">Facebook</span> </a> <a class="button button-clear button-sm has-inner-focus button-block text-decoration-none justify-content-flex-start share-twitter" data-bi-name="twitter" data-page-action-item="overflow-all"> <span class="icon" aria-hidden="true"> <span class="docon docon-xlogo-share font-size-xxs"></span> </span> <span class="margin-left-xxs">x.com</span> </a> <a class="button button-clear button-sm has-inner-focus button-block text-decoration-none justify-content-flex-start share-linkedin" data-bi-name="linkedin" data-page-action-item="overflow-all"> <span class="icon" aria-hidden="true"> <span class="docon docon-linked-in-logo font-size-sm color-primary"></span> </span> <span class="margin-left-xxs">LinkedIn</span> </a> <a class="button button-clear button-sm button-block has-inner-focus text-decoration-none justify-content-flex-start margin-bottom-xxs share-email" data-bi-name="email" data-page-action-item="overflow-all"> <span class="icon" aria-hidden="true"> <span class="docon docon-mail-message font-size-sm color-primary"></span> </span> <span class="margin-left-xxs">Email</span> </a><hr /> <button class="button button-block button-clear button-sm justify-content-flex-start has-inner-focus margin-top-xxs" title="Print" type="button" aria-label="Print" data-bi-name="print" data-page-action-item="overflow-all" data-popover-close data-print-page data-check-hidden="true"> <span class="icon" aria-hidden="true"> <span class="docon docon-print font-size-sm color-primary"></span> </span> <span class="margin-left-xxs">Print</span> </button> </div> </details> </div></div> </div> <!-- end article-header --><div> <button type="button" class="border contents-button button button-clear button-sm is-hidden-tablet has-inner-focus" data-bi-name="contents-expand" data-contents-button hidden> <span class="icon"> <span class="docon docon-editor-list-bullet" aria-hidden="true"></span> </span><span class="contents-expand-title">Table of contents</span></button> </div><!-- end mobile-contents button --> <div class="content "><h1 id="tutorial-stream-live-with-media-services-by-using-net-70">Tutorial: Stream live with Media Services by using .NET 7.0</h1><div class="display-flex justify-content-space-between align-items-center flex-wrap-wrap page-metadata-container"> <div class="margin-right-xxs"> <ul class="metadata page-metadata" data-bi-name="page info" lang="en-us" dir="ltr"><li>Article</li><li class="visibility-hidden-visual-diff"><time class="is-invisible" data-article-date aria-label="Article review date" datetime="2023-07-17T08:00:00Z" data-article-date-source="calculated">07/17/2023</time> </li><li class="contributors-holder display-none-print"> <button aria-label="View all contributors" class="contributors-button link-button" data-bi-name="contributors" title="View all contributors">1 contributor</button> </li></ul> </div> <div id="user-feedback" class="margin-block-xxs display-none-print" data-hide-on-archived> <button id="user-feedback-button" data-test-id="conceptual-feedback-button" class="button button-sm button-clear button-primary" type="button" data-bi-name="user-feedback-button" data-user-feedback-button > <span class="icon" aria-hidden="true"> <span class="docon docon-like"></span> </span> <span>Feedback</span> </button> </div></div><nav id="center-doc-outline" class="doc-outline is-hidden-desktop display-none-print margin-bottom-sm" data-bi-name="intopic toc" aria-label="In this article"> <h2 id="ms--in-this-article" class="title is-6 margin-block-xs">In this article</h2> </nav><!-- <content> --><p><img src="media/media-services-api-logo/azure-media-services-logo-v3.svg" alt="Media Services logo v3" data-linktype="relative-path"><br></p><hr color="#5ea0ef" size="10"><p></p> <div class="WARNING"> <p>Warning</p> <p>Azure Media Services will be retired June 30th, 2024. For more information, see the <a href="azure-media-services-retirement" data-linktype="relative-path">AMS Retirement Guide</a>.</p> </div> <p>In Azure Media Services, <a href="/en-us/rest/api/media/liveevents" data-linktype="absolute-path">live events</a> are responsible for processing live streaming content. A live event provides an input endpoint (ingest URL) that you then provide to a live encoder. The live event receives input streams from the live encoder using the RTMP/S or Smooth Streaming protocols and makes them available for streaming through one or more <a href="/en-us/rest/api/media/streamingendpoints" data-linktype="absolute-path">streaming endpoints</a>. Live events also provide a preview endpoint (preview URL) that you use to preview and validate your stream before further processing and delivery.</p> <p>This tutorial shows how to use .NET 7.0 to create a <em>pass-through</em> live event. Pass-through live events are useful when you have an encoder that is capable of multi-bitrate, GOP aligned encoding on premises. It can a way to reduce cloud costs. If you wish to reduce bandwidth and send a single bitrate stream to the cloud for multi-bitrate encoding, you can use a transcoding live event with the 720P or 1080P encoding presets.</p> <p>In this tutorial, you will:</p> <ul> <li>Download a sample project.</li> <li>Examine the code that performs live streaming.</li> <li>Watch the event with Azure Media Player on the <a href="https://ampdemo.azureedge.net/" data-linktype="external">Media Player demo site</a>.</li> <li>Set up Event Grid to monitor the live event.</li> <li>Clean up resources.</li> </ul> <h2 id="prerequisites">Prerequisites</h2> <p>You need the following items to complete the tutorial:</p> <ul> <li>Install <a href="https://code.visualstudio.com/" data-linktype="external">Visual Studio Code for Windows/macOS/Linux</a> or <a href="https://visualstudio.microsoft.com/" data-linktype="external">Visual Studio 2022 for Windows or Mac</a>.</li> <li>Install <a href="https://dotnet.microsoft.com/download" data-linktype="external">.NET 7.0 SDK</a></li> <li><a href="account-create-how-to" data-linktype="relative-path">Create a Media Services account</a>. Be sure to copy the <strong>API Access</strong> details for the account name, subscription ID, and resource group name in JSON format or store the values needed to connect to the Media Services account in the JSON file format used in this <code>appsettings.json</code> file.</li> <li>Follow the steps in <a href="access-api-howto" data-linktype="relative-path">Access the Azure Media Services API with the Azure CLI</a> and save the details. You'll need to use the account name, subscription Id, and resource group name in this sample, and enter them into the <code>appsettings.json</code> file.</li> </ul> <p>You also need these items for live-streaming software:</p> <ul> <li>A camera or a device (like a laptop) that's used to broadcast an event.</li> <li>An on-premises software encoder that encodes your camera stream and sends it to the Media Services live-streaming service through the Real-Time Messaging Protocol (RTMP/S). For more information, see <a href="encode-recommended-on-premises-live-encoders" data-linktype="relative-path">Recommended on-premises live encoders</a>. The stream has to be in RTMP/S or Smooth Streaming format. This sample assumes that you'll use Open Broadcaster Software (OBS) Studio to broadcast RTMP/S to the ingest endpoint. <a href="https://obsproject.com/download" data-linktype="external">Install OBS Studio</a>.</li> <li>Alternatively, you can try the <a href="live-event-obs-quickstart" data-linktype="relative-path">OBS Quickstart</a> to test the entire process with the Azure portal first.</li> </ul> <p>For monitoring the live event using Event Grid and Event Hubs, you can: 1. Follow the steps in <a href="monitor-events-portal-how-to" data-linktype="relative-path">Create and monitor Media Services events with Event Grid using the Azure portal</a> or, 1. Follow the steps near the end of this tutorial in the <a href="#monitoring-live-events-using-event-grid-and-event-hubs" data-linktype="self-bookmark">Monitoring Live Events using Event Grid and Event Hubs</a> section of this article.</p> <div class="TIP"> <p>Tip</p> <p>Review <a href="stream-live-streaming-concept" data-linktype="relative-path">Live streaming with Media Services v3</a> before proceeding.</p> </div> <h2 id="download-and-configure-the-sample">Download and configure the sample</h2> <p>Clone the GitHub repository that contains the live-streaming .NET sample to your machine by using the following command:</p> <pre><code class="lang-bash">git clone https://github.com/Azure-Samples/media-services-v3-dotnet.git </code></pre> <p>The live-streaming sample is in the <a href="https://github.com/Azure-Samples/media-services-v3-dotnet/tree/main/Live/LiveEventWithDVR" data-linktype="external">Live/LiveEventWithDVR</a> folder.</p> <p>Open <code>appsettings.json</code> in your downloaded project. Replace the values with account name, subscription Id and the resource group name.</p> <div class="IMPORTANT"> <p>Important</p> <p>This sample uses a unique suffix for each resource. If you cancel the debugging or terminate the app without running it through, you'll end up with multiple live events in your account. Be sure to stop the running live events. Otherwise, <em>you'll be billed</em>!</p> </div> <h2 id="start-using-media-services-apis-with-the-net-sdk">Start using Media Services APIs with the .NET SDK</h2> <p>Program.cs creates a reference to the Media Services account resource, using the options from <code>appsettings.json</code>:</p> <pre><code class="lang-.NET">var mediaServicesResourceId = MediaServicesAccountResource.CreateResourceIdentifier( subscriptionId: options.AZURE_SUBSCRIPTION_ID.ToString(), resourceGroupName: options.AZURE_RESOURCE_GROUP, accountName: options.AZURE_MEDIA_SERVICES_ACCOUNT_NAME); var credential = new DefaultAzureCredential(includeInteractiveCredentials: true); var armClient = new ArmClient(credential); var mediaServicesAccount = armClient.GetMediaServicesAccountResource(mediaServicesResourceId); </code></pre> <h2 id="create-a-live-event">Create a live event</h2> <p>This section shows how to create a <em>pass-through</em> type of live event (LiveEventEncodingType set to None). For information about the available types, see <a href="live-event-concept" data-linktype="relative-path">Live event types</a>. If you want to reduce your overall ingest bandwidth, or you don't have an on-premises multi-bitrate transcoder, you can use a live transcoding event for 720p or 1080p adaptive bitrate cloud encoding.</p> <p>You might want to specify the following things when you're creating the live event:</p> <ul> <li><p><strong>The ingest protocol for the live event</strong>. Currently, the RTMPS, and Smooth Streaming protocols are supported. You can't change the protocol option while the live event is running. If you need different protocols, create a separate live event for each streaming protocol.</p> </li> <li><p><strong>IP restrictions on the ingest and preview</strong>. You can define the IP addresses that are allowed to ingest a video to this live event. Allowed IP addresses can be specified as one of these choices:</p> <ul> <li><p>A single IP address (for example, 10.0.0.1 or 2001:db8::1)</p> </li> <li><p>An IP range that uses an IP address and a Classless Inter-Domain Routing (CIDR) subnet mask (for example, 10.0.0.1/22 or 2001:db8::/48)</p> </li> <li><p>An IP range that uses an IP address and a dotted decimal subnet mask (for example, 10.0.0.1 255.255.252.0)</p> <p>If no IP addresses are specified and there's no rule definition, then no IP address will be allowed. To allow any IP address, create a rule and set 0.0.0.0/0 and ::/0. The IP addresses have to be in one of the following formats: IPv4 or IPv6 addresses with four numbers or a CIDR address range. For more information, see <a href="drm-content-protection-key-delivery-ip-allow" data-linktype="relative-path">Restrict access to DRM license and AES key delivery using IP allowlists</a>.</p> </li> </ul> </li> <li><p><strong>Autostart on an event as you create it</strong>. When autostart is set to true, the live event will start after creation. That means the billing starts as soon as the live event starts running. You must explicitly call <code>Stop</code> on the live event resource to halt further billing. For more information, see <a href="live-event-states-billing-concept" data-linktype="relative-path">Live event states and billing</a>.</p> <p>Standby modes are available to start the live event in a lower-cost "allocated" state that makes it faster to move to a running state. It's useful for situations like hot pools that need to hand out channels quickly to streamers.</p> </li> <li><p><strong>A static host name and a unique GUID</strong>. For an ingest URL to be predictive and easier to maintain in a hardware-based live encoder, set the <code>useStaticHostname</code> property to true. For detailed information, see <a href="live-event-concept" data-linktype="relative-path">Live event ingest URLs</a>.</p> <pre><code class="lang-csharp" name="Main">var liveEvent = await mediaServicesAccount.GetMediaLiveEvents().CreateOrUpdateAsync( WaitUntil.Completed, liveEventName, new MediaLiveEventData(mediaServicesAccount.Get().Value.Data.Location) { Description = "Sample Live Event from the .NET SDK sample", UseStaticHostname = true, // 1) Set up the input settings for the Live event... Input = new LiveEventInput(streamingProtocol: LiveEventInputProtocol.Rtmp) { StreamingProtocol = LiveEventInputProtocol.Rtmp, AccessToken = "acf7b6ef-8a37-425f-b8fc-51c2d6a5a86a", // used to make the ingest URL unique KeyFrameIntervalDuration = TimeSpan.FromSeconds(2), IPAllowedIPs = { new IPRange { Name = "AllowAllIpV4Addresses", Address = IPAddress.Parse("0.0.0.0"), SubnetPrefixLength = 0 }, new IPRange { Name = "AllowAllIpV6Addresses", Address = IPAddress.Parse("0::"), SubnetPrefixLength = 0 } } }, // 2) Set the live event to use pass-through or cloud encoding modes... Encoding = new LiveEventEncoding() { EncodingType = LiveEventEncodingType.PassthroughBasic }, // 3) Set up the Preview endpoint for monitoring Preview = new LiveEventPreview { IPAllowedIPs = { new IPRange() { Name = "AllowAllIpV4Addresses", Address = IPAddress.Parse("0.0.0.0"), SubnetPrefixLength = 0 }, new IPRange() { Name = "AllowAllIpV6Addresses", Address = IPAddress.Parse("0::"), SubnetPrefixLength = 0 } } }, // 4) Set up more advanced options on the live event. Low Latency is the most common one. Set // this to Default or Low Latency. When using Low Latency mode, you must configure the Azure // Media Player to use the quick start heuristic profile or you won't notice the change. In // the AMP player client side JS options, set - heuristicProfile: "Low Latency Heuristic // Profile". To use low latency optimally, you should tune your encoder settings down to 1 // second GOP size instead of 2 seconds. StreamOptions = { StreamOptionsFlag.LowLatency }, // 5) Optionally enable live transcriptions if desired. This is only supported on // PassthroughStandard, and the transcoding live event types. It is not supported on Basic // pass-through type. // WARNING: This is extra cost, so please check pricing before enabling. //Transcriptions = //{ // new LiveEventTranscription // { // // The value should be in BCP-47 format (e.g: 'en-US'). See https://go.microsoft.com/fwlink/?linkid=2133742 // Language = "en-us", // TrackName = "English" // set the name you want to appear in the output manifest // } //} }, autoStart: false); </code></pre></li> </ul> <h2 id="get-ingest-urls">Get ingest URLs</h2> <p>After the Live Event is created, you can get ingest URLs that you'll provide to the live encoder. The encoder uses these URLs to input a live stream.</p> <pre><code class="lang-csharp" name="Main">// Get the RTMP ingest URL. The endpoints is a collection of RTMP primary and secondary, // and RTMPS primary and secondary URLs. Console.WriteLine($"The RTMP ingest URL to enter into OBS Studio is:"); Console.WriteLine(liveEvent.Data.Input.Endpoints.First(x => x.Uri.Scheme == "rtmps").Uri); Console.WriteLine("Make sure to enter a Stream Key into the OBS Studio settings. It can be"); Console.WriteLine("any value or you can repeat the accessToken used in the ingest URL path."); Console.WriteLine(); </code></pre><h2 id="get-the-preview-url">Get the preview URL</h2> <p>Use <code>previewEndpoint</code> to preview and verify that the input from the encoder is being received.</p> <div class="IMPORTANT"> <p>Important</p> <p>Make sure that the video is flowing to the preview URL before you continue.</p> </div> <pre><code class="lang-csharp" name="Main">// Use the previewEndpoint to preview and verify that the input from the encoder is actually // being received The preview endpoint URL also support the addition of various format strings // for HLS (format=m3u8-cmaf) and DASH (format=mpd-time-cmaf) for example. The default manifest // is Smooth. string previewEndpoint = liveEvent.Data.Preview.Endpoints.First().Uri.ToString(); Console.WriteLine($"The preview URL is:"); Console.WriteLine(previewEndpoint); Console.WriteLine(); Console.WriteLine($"Open the live preview in your browser and use the Azure Media Player to monitor the preview playback:"); Console.WriteLine($"https://ampdemo.azureedge.net/?url={HttpUtility.UrlEncode(previewEndpoint)}&heuristicprofile=lowlatency"); Console.WriteLine(); Console.WriteLine("Start the live stream now, sending the input to the ingest URL and verify"); Console.WriteLine("that it is arriving with the preview URL."); Console.WriteLine("IMPORTANT: Make sure that the video is flowing to the Preview URL before continuing!"); Console.WriteLine("Press enter to continue..."); Console.ReadLine(); </code></pre><h2 id="create-and-manage-live-events-and-live-outputs">Create and manage live events and live outputs</h2> <p>After the live stream from the on-premises encoder is streaming to the live event, you can begin the live event by creating an asset, live output, and streaming locator. The stream is archived and is available to viewers through the streaming endpoint.</p> <p>The next section will walk through the creation of the asset and the live output.</p> <h3 id="create-an-asset">Create an asset</h3> <p>Create an asset for the live output to use.</p> <pre><code class="lang-csharp" name="Main">// Create an Asset for the Live Output to use. Think of this as the "tape" that will be recorded // to. The asset entity points to a folder/container in your Azure Storage account Console.Write($"Creating the output Asset '{assetName}'...".PadRight(60)); var asset = (await mediaServicesAccount.GetMediaAssets().CreateOrUpdateAsync( WaitUntil.Completed, assetName, new MediaAssetData { Description = "My video description" })).Value; Console.WriteLine("Done"); </code></pre><h3 id="create-a-live-output">Create a live output</h3> <p>Live outputs start when they're created and stop when they're deleted. When you delete the live output, you're not deleting the output asset or content in the asset. The asset with the recording is available for on-demand streaming as long as it exists and there's a streaming locator associated with it.</p> <pre><code class="lang-csharp" name="Main">// Create the Live Output - think of this as the "tape recorder for the live event". Live // outputs are optional, but are required if you want to archive the event to storage, use the // asset for on-demand playback later, or if you want to enable cloud DVR time-shifting. We will // use the asset created above for the "tape" to record to. Console.Write($"Creating Live Output...".PadRight(60)); var liveOutput = (await liveEvent.GetMediaLiveOutputs().CreateOrUpdateAsync( WaitUntil.Completed, liveOutputName, new MediaLiveOutputData { AssetName = asset.Data.Name, // The HLS and DASH manifest file name. This is recommended to // set if you want a deterministic manifest path up front. // archive window can be set from 3 minutes to 25 hours. // Content that falls outside of ArchiveWindowLength is // continuously discarded from storage and is non-recoverable. // For a full event archive, set to the maximum, 25 hours. ManifestName = manifestName, ArchiveWindowLength = TimeSpan.FromHours(1) })).Value; Console.WriteLine("Done"); </code></pre><h2 id="create-a-streaming-locator">Create a streaming locator</h2> <div class="NOTE"> <p>Note</p> <p>When your Media Services account is created, a default streaming endpoint is added to your account in the stopped state. To start streaming your content and take advantage of <a href="encode-dynamic-packaging-concept" data-linktype="relative-path">dynamic packaging</a> and dynamic encryption, the streaming endpoint from which you want to stream content has to be in the running state.</p> </div> <p>You publish an asset by creating a streaming locator. The live event (up to the DVR window length) is viewable until the streaming locator's expiration or deletion, whichever comes first. It's how you make the video available for your viewing audience to see live and on demand. The same URL can be used to watch the live event, the DVR window, or the on-demand asset when the live event is finished and the live output is deleted.</p> <pre><code class="lang-csharp" name="Main">var streamingLocator = (await mediaServicesAccount.GetStreamingLocators().CreateOrUpdateAsync( WaitUntil.Completed, streamingLocatorName, new StreamingLocatorData { AssetName = asset.Data.Name, StreamingPolicyName = "Predefined_ClearStreamingOnly", Filters = { filter.Data.Name } })).Value; </code></pre><h2 id="watch-the-event">Watch the event</h2> <p>Run the code. Use the output streaming URLs to watch your live event. Copy the streaming locator URL. You can use a media player of your choice. You can use the <a href="https://ampdemo.azureedge.net/" data-linktype="external">Media Player demo site</a> to test your stream. Enter the URL into the URL field and select <strong>Update player</strong>.</p> <h2 id="monitoring-live-events-using-event-grid-and-event-hubs">Monitoring Live Events using Event Grid and Event Hubs</h2> <p>The sample project can use Event Grid and Event Hubs to monitor the Live Event. You can set up and use Event Grid using the following</p> <p>To enable monitoring:</p> <ol> <li>Use the Azure portal to create Event Hubs Namespace and an Event Hubs <ol> <li>Search for “Event Hubs” using the text box at the top of the Azure portal.</li> <li>Select <strong>Event Hub</strong> from the list, then follow the instructions to create an Event Hubs Namespace.</li> <li>Navigate to the Event Hubs Namespace resource.</li> <li>Select <strong>Event Hubs</strong> from the <strong>Entities</strong> section of the portal menu.</li> <li>Create an Event Hubs in the Event Hubs namespace.</li> <li>Navigate to the Event Hubs resource.</li> <li>Select <strong>Access control</strong> then <strong>Add</strong>, then <strong>Add role assignment</strong>.</li> <li>Select the <strong>Azure Event Hubs Data Receiver</strong> then grant the access to yourself.</li> <li>Select <strong>Access control</strong> then <strong>Add</strong>, then <strong>Add role assignment</strong>.</li> <li>Select the <strong>Azure Event Hubs Data Sender</strong> then grant it to the Managed Identity created for the Media Services account.</li> </ol> </li> <li>Use the Azure portal to create an Azure Storage account. <ol> <li>After creating the storage account, navigate to the Storage Account resource.</li> <li>Select <strong>Access control</strong> then <strong>Add</strong>, then <strong>Add role assignment</strong>.</li> <li>Select the <strong>Storage Blob Data Contributor</strong> then grant this access to yourself.</li> </ol> </li> <li>Create an Event Subscription <ol> <li>Navigate to the Media Services account.</li> <li>Select <strong>Events</strong> from the portal menu.</li> <li>Select <strong>+ Event Subscription</strong>.</li> <li>Enter a subscription name and a system article name.</li> <li>Set the <strong>Endpoint Type</strong> to <code>Event Hub</code>.</li> <li>Set the Event Hubs to the previously created Event Hubs and set the Managed Identity to the identity that was previously granted Sender access to the Event Hubs</li> </ol> </li> <li>Update the <code>appsetttings.json</code> file. <ol> <li>Set EVENT_HUB_NAMESPACE to the full name of the namespace. It should be similar to <code>myeventhub.servicebus.windows.net</code>.</li> <li>Set EVENT_HUB_NAME.</li> <li>Set AZURE_STORAGE_ACCOUNT_NAME.</li> </ol> </li> </ol> <p>Run the sample again. With Event Hubs integration enabled, the sample logs events when the encoder connects and disconnects from the Live Event. Various other events are also logged.</p> <p>After running the sample, delete the Event Hubs and storage account if they're no longer needed.</p> <h2 id="clean-up-resources-in-your-media-services-account">Clean up resources in your Media Services account</h2> <p>If you're done streaming events and want to clean up the resources provisioned earlier, use the following procedure:</p> <ol> <li>Stop streaming from the encoder.</li> <li>Stop the live event. After the live event is stopped, it won't incur any charges. When you need to start it again, the same ingest URL can be used so you won't need to reconfigure your encoder.</li> <li>Stop the streaming endpoint, unless you want to continue to provide the archive of your live event as an on-demand stream. If the live event is in a stopped state, it won't incur any charges.</li> </ol> <pre><code class="lang-csharp" name="Main">if (liveOutput != null) { Console.Write("Deleting the Live Output...".PadRight(60)); await liveOutput.DeleteAsync(WaitUntil.Completed); Console.WriteLine("Done"); } if (liveEvent?.Data.ResourceState == LiveEventResourceState.Running) { Console.Write("Stopping the Live Event...".PadRight(60)); await liveEvent.StopAsync(WaitUntil.Completed, new LiveEventActionContent() { RemoveOutputsOnStop = true }); Console.WriteLine("Done"); } if (liveEvent != null) { Console.Write("Deleting the Live Event...".PadRight(60)); await liveEvent.DeleteAsync(WaitUntil.Completed); Console.WriteLine("Done"); } if (streamingLocator != null) { Console.Write("Deleting the Streaming Locator...".PadRight(60)); await streamingLocator.DeleteAsync(WaitUntil.Completed); Console.WriteLine("Done"); } if (asset != null) { Console.Write("Deleting the Asset...".PadRight(60)); await asset.DeleteAsync(WaitUntil.Completed); Console.WriteLine("Done"); } </code></pre><h2 id="clean-up-remaining-resources">Clean up remaining resources</h2> <p>If you no longer need the Media Services and storage accounts that you created for this tutorial, delete the resource group that you created earlier.</p> <p>Run the following CLI command:</p> <pre><code class="lang-cli"> az group delete --name amsResourceGroup </code></pre> <h2 id="get-help-and-support">Get help and support</h2> <p>You can contact Media Services with questions or follow our updates by one of the following methods:</p> <ul> <li><a href="/en-us/answers/topics/azure-media-services.html" data-linktype="absolute-path">Q & A</a></li> <li><a href="https://stackoverflow.com/questions/tagged/azure-media-services" data-linktype="external">Stack Overflow</a>. Tag questions with <code>azure-media-services</code>.</li> <li><a href="https://twitter.com/MSFTAzureMedia" data-linktype="external">@MSFTAzureMedia</a> or use <a href="https://twitter.com/azuresupport" data-linktype="external">@AzureSupport</a> to request support.</li> <li>Open a support ticket through the Azure portal.</li> </ul> </div><div id="ms--inline-notifications" class="margin-block-xs" data-bi-name="inline-notification"></div><div id="assertive-live-region" role="alert" aria-live="assertive" class="visually-hidden" aria-relevant="additions" aria-atomic="true"></div> <div id="polite-live-region" role="status" aria-live="polite" class="visually-hidden" aria-relevant="additions" aria-atomic="true"></div> <!-- </content> --> </main><!-- recommendations section --><!-- end recommendations section --> <!-- feedback section --><!-- end feedback section --> <!-- feedback report section --><!-- end feedback report section --><aside id="ms--additional-resources-mobile" aria-label="Additional resources" class="display-none-desktop display-none-print" > <hr class="hr" hidden /> <h2 id="ms--additional-resources-mobile-heading" class="title is-3" hidden>Additional resources</h2> <section id="right-rail-recommendations-mobile" data-bi-name="recommendations" hidden></section> <section id="right-rail-training-mobile" data-bi-name="learning-resources-card" hidden></section> <section id="right-rail-events-mobile" data-bi-name="events-card" hidden></section> <section id="right-rail-qna-mobile" data-bi-name="qna-link-card" hidden></section> </aside><div class="border-top is-visible-interactive has-default-focus margin-top-sm "><footer id="footer-interactive" data-bi-name="footer" class="footer-layout"><div class="display-flex gap-xs flex-wrap-wrap is-full-height padding-right-lg-desktop"><a data-mscc-ic="false" class="locale-selector-link button button-sm button-clear flex-shrink-0" href="#" data-bi-name="select-locale"> <span class="icon" aria-hidden="true"> <span class="docon docon-world"></span> </span> <span class="local-selector-link-text"></span></a><div class="ccpa-privacy-link" data-ccpa-privacy-link hidden> <a href="https://aka.ms/yourcaliforniaprivacychoices" class="button button-sm button-clear flex-shrink-0" data-mscc-ic="false" data-bi-name="your-privacy-choices" > <svg role="img" aria-label="California Consumer Privacy Act (CCPA) Opt-Out Icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 14" xml:space="preserve" height="16" width="43" focusable="false" > <title>California Consumer Privacy Act (CCPA) Opt-Out Icon</title> <path d="M7.4 12.8h6.8l3.1-11.6H7.4C4.2 1.2 1.6 3.8 1.6 7s2.6 5.8 5.8 5.8z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#fff"></path> <path d="M22.6 0H7.4c-3.9 0-7 3.1-7 7s3.1 7 7 7h15.2c3.9 0 7-3.1 7-7s-3.2-7-7-7zm-21 7c0-3.2 2.6-5.8 5.8-5.8h9.9l-3.1 11.6H7.4c-3.2 0-5.8-2.6-5.8-5.8z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#06f"></path> <path d="M24.6 4c.2.2.2.6 0 .8L22.5 7l2.2 2.2c.2.2.2.6 0 .8-.2.2-.6.2-.8 0l-2.2-2.2-2.2 2.2c-.2.2-.6.2-.8 0-.2-.2-.2-.6 0-.8L20.8 7l-2.2-2.2c-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0l2.2 2.2L23.8 4c.2-.2.6-.2.8 0z" style="fill:#fff"></path> <path d="M12.7 4.1c.2.2.3.6.1.8L8.6 9.8c-.1.1-.2.2-.3.2-.2.1-.5.1-.7-.1L5.4 7.7c-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0L8 8.6l3.8-4.5c.2-.2.6-.2.9 0z" style="fill:#06f"></path> </svg> <span>Your Privacy Choices</span> </a> </div> <div class="flex-shrink-0"> <div class="dropdown has-caret-up"> <button class="dropdown-trigger button button-clear button-sm has-inner-focus theme-dropdown-trigger" aria-controls="theme-menu-interactive" aria-expanded="false" title="Theme" data-bi-name="theme"> <span class="icon"> <span class="docon docon-sun" aria-hidden="true"></span> </span> <span>Theme</span> <span class="icon expanded-indicator" aria-hidden="true"> <span class="docon docon-chevron-down-light"></span> </span> </button> <div class="dropdown-menu" id="theme-menu-interactive" role="menu"> <ul class="theme-selector padding-xxs" role="none"> <li class="theme display-block" role="menuitem"> <button class="button button-clear button-sm theme-control button-block justify-content-flex-start" data-theme-to="light"> <span class="theme-light margin-right-xxs"> <span class="theme-selector-icon border display-inline-block has-body-background" aria-hidden="true"> <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 14"> <rect width="22" height="14" class="has-fill-body-background" /> <rect x="5" y="5" width="12" height="4" class="has-fill-secondary" /> <rect x="5" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="8" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="11" y="2" width="3" height="1" class="has-fill-secondary" /> <rect x="1" y="1" width="2" height="2" class="has-fill-secondary" /> <rect x="5" y="10" width="7" height="2" rx="0.3" class="has-fill-primary" /> <rect x="19" y="1" width="2" height="2" rx="1" class="has-fill-secondary" /> </svg> </span> </span> <span>Light</span> </button> </li> <li class="theme display-block" role="menuitem"> <button class="button button-clear button-sm theme-control button-block justify-content-flex-start" data-theme-to="dark"> <span class="theme-dark margin-right-xxs"> <span class="border theme-selector-icon display-inline-block has-body-background" aria-hidden="true"> <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 14"> <rect width="22" height="14" class="has-fill-body-background" /> <rect x="5" y="5" width="12" height="4" class="has-fill-secondary" /> <rect x="5" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="8" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="11" y="2" width="3" height="1" class="has-fill-secondary" /> <rect x="1" y="1" width="2" height="2" class="has-fill-secondary" /> <rect x="5" y="10" width="7" height="2" rx="0.3" class="has-fill-primary" /> <rect x="19" y="1" width="2" height="2" rx="1" class="has-fill-secondary" /> </svg> </span> </span> <span>Dark</span> </button> </li> <li class="theme display-block" role="menuitem"> <button class="button button-clear button-sm theme-control button-block justify-content-flex-start" data-theme-to="high-contrast"> <span class="theme-high-contrast margin-right-xxs"> <span class="border theme-selector-icon display-inline-block has-body-background" aria-hidden="true"> <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 14"> <rect width="22" height="14" class="has-fill-body-background" /> <rect x="5" y="5" width="12" height="4" class="has-fill-secondary" /> <rect x="5" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="8" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="11" y="2" width="3" height="1" class="has-fill-secondary" /> <rect x="1" y="1" width="2" height="2" class="has-fill-secondary" /> <rect x="5" y="10" width="7" height="2" rx="0.3" class="has-fill-primary" /> <rect x="19" y="1" width="2" height="2" rx="1" class="has-fill-secondary" /> </svg> </span> </span> <span>High contrast</span> </button> </li> </ul> </div> </div> </div> </div> <ul class="links" data-bi-name="footerlinks"> <li class="manage-cookies-holder" hidden></li><li><a class="external-link-indicator" data-mscc-ic="false" href="/en-us/previous-versions/" data-bi-name="archivelink">Previous Versions</a></li> <li><a class="external-link-indicator" data-mscc-ic="false" href="https://techcommunity.microsoft.com/t5/microsoft-learn-blog/bg-p/MicrosoftLearnBlog" data-bi-name="bloglink">Blog</a></li> <li><a class="external-link-indicator" data-mscc-ic="false" href="/en-us/contribute/" data-bi-name="contributorGuide">Contribute</a></li><li><a class="external-link-indicator" data-mscc-ic="false" href="https://go.microsoft.com/fwlink/?LinkId=521839" data-bi-name="privacy">Privacy</a></li><li><a class="external-link-indicator" data-mscc-ic="false" href="/en-us/legal/termsofuse" data-bi-name="termsofuse">Terms of Use</a></li><li><a class="external-link-indicator" data-mscc-ic="false" href="https://www.microsoft.com/legal/intellectualproperty/Trademarks/" data-bi-name="trademarks">Trademarks</a></li><li>© Microsoft 2024</li> </ul> </footer></div></div><div id="ms--additional-resources" class="right-container column is-4-desktop display-none display-block-desktop" data-bi-name="pageactions" role="complementary" aria-label="Additional resources" > <div id="affixed-right-container" class="margin-top-sm-tablet" data-bi-name="right-column"> <h2 id="ms--additional-resources-heading" class="title is-6 margin-top-md" hidden>Additional resources</h2> <section id="right-rail-events" data-bi-name="events-card" hidden></section> <section id="right-rail-training" data-bi-name="learning-resources-card" hidden></section> <section id="right-rail-recommendations" data-bi-name="recommendations" hidden></section> <nav id="side-doc-outline" class="doc-outline" data-bi-name="intopic toc" aria-label="In this article"> <h3>In this article</h3> </nav> <section id="right-rail-qna" class="margin-top-xxs" data-bi-name="qna-link-card" hidden></section> </div> </div></div> <!--end of div.columns --> </section> <!--end of .primary-holder --> <!-- interactive container --> <aside id="interactive-container" class="interactive-container is-visible-interactive column has-body-background-dark "> </aside> <!-- end of interactive container --> </div> </div> <!--end of .mainContainer --> <section class="border-top has-default-focus is-hidden-interactive margin-top-sm "><footer id="footer" data-bi-name="footer" class="footer-layout uhf-container has-padding" role="contentinfo"><div class="display-flex gap-xs flex-wrap-wrap is-full-height padding-right-lg-desktop"><a data-mscc-ic="false" class="locale-selector-link button button-sm button-clear flex-shrink-0" href="#" data-bi-name="select-locale"> <span class="icon" aria-hidden="true"> <span class="docon docon-world"></span> </span> <span class="local-selector-link-text"></span></a><div class="ccpa-privacy-link" data-ccpa-privacy-link hidden> <a href="https://aka.ms/yourcaliforniaprivacychoices" class="button button-sm button-clear flex-shrink-0" data-mscc-ic="false" data-bi-name="your-privacy-choices" > <svg role="img" aria-label="California Consumer Privacy Act (CCPA) Opt-Out Icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 14" xml:space="preserve" height="16" width="43" focusable="false" > <title>California Consumer Privacy Act (CCPA) Opt-Out Icon</title> <path d="M7.4 12.8h6.8l3.1-11.6H7.4C4.2 1.2 1.6 3.8 1.6 7s2.6 5.8 5.8 5.8z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#fff"></path> <path d="M22.6 0H7.4c-3.9 0-7 3.1-7 7s3.1 7 7 7h15.2c3.9 0 7-3.1 7-7s-3.2-7-7-7zm-21 7c0-3.2 2.6-5.8 5.8-5.8h9.9l-3.1 11.6H7.4c-3.2 0-5.8-2.6-5.8-5.8z" style="fill-rule:evenodd;clip-rule:evenodd;fill:#06f"></path> <path d="M24.6 4c.2.2.2.6 0 .8L22.5 7l2.2 2.2c.2.2.2.6 0 .8-.2.2-.6.2-.8 0l-2.2-2.2-2.2 2.2c-.2.2-.6.2-.8 0-.2-.2-.2-.6 0-.8L20.8 7l-2.2-2.2c-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0l2.2 2.2L23.8 4c.2-.2.6-.2.8 0z" style="fill:#fff"></path> <path d="M12.7 4.1c.2.2.3.6.1.8L8.6 9.8c-.1.1-.2.2-.3.2-.2.1-.5.1-.7-.1L5.4 7.7c-.2-.2-.2-.6 0-.8.2-.2.6-.2.8 0L8 8.6l3.8-4.5c.2-.2.6-.2.9 0z" style="fill:#06f"></path> </svg> <span>Your Privacy Choices</span> </a> </div> <div class="flex-shrink-0"> <div class="dropdown has-caret-up"> <button class="dropdown-trigger button button-clear button-sm has-inner-focus theme-dropdown-trigger" aria-controls="theme-menu" aria-expanded="false" title="Theme" data-bi-name="theme"> <span class="icon"> <span class="docon docon-sun" aria-hidden="true"></span> </span> <span>Theme</span> <span class="icon expanded-indicator" aria-hidden="true"> <span class="docon docon-chevron-down-light"></span> </span> </button> <div class="dropdown-menu" id="theme-menu" role="menu"> <ul class="theme-selector padding-xxs" role="none"> <li class="theme display-block" role="menuitem"> <button class="button button-clear button-sm theme-control button-block justify-content-flex-start" data-theme-to="light"> <span class="theme-light margin-right-xxs"> <span class="theme-selector-icon border display-inline-block has-body-background" aria-hidden="true"> <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 14"> <rect width="22" height="14" class="has-fill-body-background" /> <rect x="5" y="5" width="12" height="4" class="has-fill-secondary" /> <rect x="5" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="8" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="11" y="2" width="3" height="1" class="has-fill-secondary" /> <rect x="1" y="1" width="2" height="2" class="has-fill-secondary" /> <rect x="5" y="10" width="7" height="2" rx="0.3" class="has-fill-primary" /> <rect x="19" y="1" width="2" height="2" rx="1" class="has-fill-secondary" /> </svg> </span> </span> <span>Light</span> </button> </li> <li class="theme display-block" role="menuitem"> <button class="button button-clear button-sm theme-control button-block justify-content-flex-start" data-theme-to="dark"> <span class="theme-dark margin-right-xxs"> <span class="border theme-selector-icon display-inline-block has-body-background" aria-hidden="true"> <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 14"> <rect width="22" height="14" class="has-fill-body-background" /> <rect x="5" y="5" width="12" height="4" class="has-fill-secondary" /> <rect x="5" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="8" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="11" y="2" width="3" height="1" class="has-fill-secondary" /> <rect x="1" y="1" width="2" height="2" class="has-fill-secondary" /> <rect x="5" y="10" width="7" height="2" rx="0.3" class="has-fill-primary" /> <rect x="19" y="1" width="2" height="2" rx="1" class="has-fill-secondary" /> </svg> </span> </span> <span>Dark</span> </button> </li> <li class="theme display-block" role="menuitem"> <button class="button button-clear button-sm theme-control button-block justify-content-flex-start" data-theme-to="high-contrast"> <span class="theme-high-contrast margin-right-xxs"> <span class="border theme-selector-icon display-inline-block has-body-background" aria-hidden="true"> <svg class="svg" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 22 14"> <rect width="22" height="14" class="has-fill-body-background" /> <rect x="5" y="5" width="12" height="4" class="has-fill-secondary" /> <rect x="5" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="8" y="2" width="2" height="1" class="has-fill-secondary" /> <rect x="11" y="2" width="3" height="1" class="has-fill-secondary" /> <rect x="1" y="1" width="2" height="2" class="has-fill-secondary" /> <rect x="5" y="10" width="7" height="2" rx="0.3" class="has-fill-primary" /> <rect x="19" y="1" width="2" height="2" rx="1" class="has-fill-secondary" /> </svg> </span> </span> <span>High contrast</span> </button> </li> </ul> </div> </div> </div> </div> <ul class="links" data-bi-name="footerlinks"> <li class="manage-cookies-holder" hidden></li><li><a class="external-link-indicator" data-mscc-ic="false" href="/en-us/previous-versions/" data-bi-name="archivelink">Previous Versions</a></li> <li><a class="external-link-indicator" data-mscc-ic="false" href="https://techcommunity.microsoft.com/t5/microsoft-learn-blog/bg-p/MicrosoftLearnBlog" data-bi-name="bloglink">Blog</a></li> <li><a class="external-link-indicator" data-mscc-ic="false" href="/en-us/contribute/" data-bi-name="contributorGuide">Contribute</a></li><li><a class="external-link-indicator" data-mscc-ic="false" href="https://go.microsoft.com/fwlink/?LinkId=521839" data-bi-name="privacy">Privacy</a></li><li><a class="external-link-indicator" data-mscc-ic="false" href="/en-us/legal/termsofuse" data-bi-name="termsofuse">Terms of Use</a></li><li><a class="external-link-indicator" data-mscc-ic="false" href="https://www.microsoft.com/legal/intellectualproperty/Trademarks/" data-bi-name="trademarks">Trademarks</a></li><li>© Microsoft 2024</li> </ul> </footer> </section> <div id="action-panel" role="region" aria-label="Action Panel" class="action-panel has-default-focus" tabindex="-1"></div> </body> </html>