Пример #1
0
        public breakschedule()
        {
            this.InitializeComponent();
            MediaPlaybackItem moviePlaybackItem = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/fishes.wmv")));
            MediaBreak        midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromSeconds(3));

            midrollMediaBreak.PlaybackList.Items.Add(
                new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/ladybug.wmv"))));
            moviePlaybackItem.BreakSchedule.InsertMidrollBreak(midrollMediaBreak);

            /*MediaBreak preRollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
             * MediaPlaybackItem prerollAd = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/ladybug.wmv")));
             * prerollAd.CanSkip = false;
             * preRollMediaBreak.PlaybackList.Items.Add(prerollAd);
             * moviePlaybackItem.BreakSchedule.PrerollBreak = preRollMediaBreak;*/

            /*midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Replace, TimeSpan.FromSeconds(5));
             * MediaPlaybackItem ad = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_3.mp4")),
             *  TimeSpan.FromSeconds(6),
             *  TimeSpan.FromSeconds(10));
             * ad.CanSkip = false;
             * midrollMediaBreak.PlaybackList.Items.Add(ad);*/

            _mediaPlayer.Source = moviePlaybackItem;
            mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
            _mediaPlayer.AutoPlay = true;
            _mediaPlayer.BreakManager.BreakStarted     += BreakManager_BreakStarted;
            _mediaPlayer.BreakManager.BreakEnded       += BreakManager_BreakEnded;
            _mediaPlayer.BreakManager.BreakSkipped     += BreakManager_BreakSkipped;
            _mediaPlayer.BreakManager.BreaksSeekedOver += BreakManager_BreaksSeekedOver;
        }
Пример #2
0
        //http://www.fabrikam.com/
        private void CreateMediaBreakSchedule()
        {
            // <SnippetMoviePlaybackItem>
            MediaPlaybackItem moviePlaybackItem =
                new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/movie.mkv")));
            // </SnippetMoviePlaybackItem>

            // <SnippetPreRollBreak>
            MediaBreak        preRollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
            MediaPlaybackItem prerollAd         =
                new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/preroll_ad.mp4")));

            prerollAd.CanSkip = false;
            preRollMediaBreak.PlaybackList.Items.Add(prerollAd);

            moviePlaybackItem.BreakSchedule.PrerollBreak = preRollMediaBreak;
            // </SnippetPreRollBreak>


            // <SnippetPostRollBreak>
            MediaBreak        postrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
            MediaPlaybackItem postRollAd         =
                new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/postroll_ad.mp4")));

            postrollMediaBreak.PlaybackList.Items.Add(postRollAd);

            moviePlaybackItem.BreakSchedule.PostrollBreak = postrollMediaBreak;
            // </SnippetPostRollBreak>


            // <SnippetMidrollBreak>
            MediaBreak midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromMinutes(10));

            midrollMediaBreak.PlaybackList.Items.Add(
                new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_1.mp4"))));
            midrollMediaBreak.PlaybackList.Items.Add(
                new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_2.mp4"))));
            moviePlaybackItem.BreakSchedule.InsertMidrollBreak(midrollMediaBreak);
            // </SnippetMidrollBreak>

            // <SnippetMidrollBreak2>
            midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Replace, TimeSpan.FromMinutes(20));
            MediaPlaybackItem ad =
                new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://www.fabrikam.com/midroll_ad_3.mp4")),
                                      TimeSpan.FromSeconds(30),
                                      TimeSpan.FromSeconds(15));

            ad.CanSkip = false;
            midrollMediaBreak.PlaybackList.Items.Add(ad);
            // </SnippetMidrollBreak2>


            // <SnippetPlay>
            _mediaPlayer          = new MediaPlayer();
            _mediaPlayer.AutoPlay = true;
            _mediaPlayer.Source   = moviePlaybackItem;
            mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
            // </SnippetPlay>
        }
Пример #3
0
        // </SnippetBreakStarted>

        // <SnippetGetCurrentBreakItemIndex>
        public int GetCurrentBreakItemIndex()
        {
            MediaBreak mediaBreak = _mediaPlayer.BreakManager.CurrentBreak;

            if (!(mediaBreak is null))
            {
                return((int)mediaBreak.PlaybackList.CurrentItemIndex);
            }
Пример #4
0
        // <SnippetBreakStarted>
        private async void BreakManager_BreakStarted(MediaBreakManager sender, MediaBreakStartedEventArgs args)
        {
            MediaBreak currentBreak = sender.CurrentBreak;
            var        currentIndex = currentBreak.PlaybackList.CurrentItemIndex;
            var        itemCount    = currentBreak.PlaybackList.Items.Count;

            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
                                      statusTextBlock.Text = $"Playing ad {currentIndex + 1} of {itemCount}");
        }
Пример #5
0
        private async Task CreateMediaBreakScheduleTest()
        {
            //SnippetMoviePlaybackItem
            MediaPlaybackItem moviePlaybackItem = await GetMoviePlaybackItem();

            ///SnippetMoviePlaybackItem>

            //SnippetPreRollBreak
            MediaBreak        preRollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
            MediaPlaybackItem prerollAd         = await GetAdPlaybackItem();

            prerollAd.CanSkip = false;
            preRollMediaBreak.PlaybackList.Items.Add(prerollAd);

            moviePlaybackItem.BreakSchedule.PrerollBreak = preRollMediaBreak;
            ///SnippetPreRollBreak

            /*
             * //SnippetPostRollBreak
             * MediaBreak postrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
             * MediaPlaybackItem postRollAd = await GetAdPlaybackItem();
             * postrollMediaBreak.PlaybackList.Items.Add(postRollAd);
             *
             * moviePlaybackItem.BreakSchedule.PostrollBreak = postrollMediaBreak;
             * ///SnippetPostRollBreak
             *
             *
             * ///SnippetMidrollBreak
             * MediaBreak midrollMediaBreak = new MediaBreak(MediaBreakInsertionMethod.Replace, TimeSpan.FromSeconds(10));
             * midrollMediaBreak.PlaybackList.Items.Add(await GetAdPlaybackItem());
             * midrollMediaBreak.PlaybackList.Items.Add(await GetAdPlaybackItem());
             * //MediaPlaybackItem ad = new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("http://myserver/midroll_ad_3.mp4")),
             * //TimeSpan.FromSeconds(5),
             * //TimeSpan.FromSeconds(15));
             * //MediaPlaybackItem ad = await GetScheduledMediaPlaybackItem();
             * //ad.CanSkip = false;
             * //midrollMediaBreak.PlaybackList.Items.Add(ad);
             *
             * moviePlaybackItem.BreakSchedule.InsertMidrollBreak(midrollMediaBreak);
             *
             * ///SnippetMidrollBreak
             */
            //Play
            _mediaPlayer          = new MediaPlayer();
            _mediaPlayer.AutoPlay = true;
            _mediaPlayer.Source   = moviePlaybackItem;
            mediaPlayerElement.SetMediaPlayer(_mediaPlayer);
            ///Play
        }
Пример #6
0
        // </SnippetBreakStarted>

        // <SnippetGetCurrentBreakItemIndex>
        public int GetCurrentBreakItemIndex()
        {
            MediaBreak mediaBreak = _mediaPlayer.BreakManager.CurrentBreak;

            if (mediaBreak != null)
            {
                return((int)mediaBreak.PlaybackList.CurrentItemIndex);
            }
                        else
            {
                            {
                    return(-1);
                }
            }
        }
Пример #7
0
        private async void BreakManager_BreakSkipped(MediaBreakManager sender, MediaBreakSkippedEventArgs args)
        {
            // Update UI to show that the MediaBreak is no longer playing
            await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => statusTextBlock.Text = "");

            MediaPlaybackItem currentItem = _mediaPlayer.Source as MediaPlaybackItem;

            if (!(currentItem.BreakSchedule.PrerollBreak is null) &&
                currentItem.BreakSchedule.PrerollBreak == args.MediaBreak)
            {
                MediaBreak mediaBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt, TimeSpan.FromMinutes(10));
                mediaBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/ladybug.wmv"))));
                currentItem.BreakSchedule.InsertMidrollBreak(mediaBreak);
            }
        }
Пример #8
0
        /// <summary>
        /// This function attempts to parse the SCTE-35 payload, then schedule an appropriately offset Ad using the MediaBreak APIs
        /// </summary>
        /// <param name="timedMetadataTrack">Track which fired the cue</param>
        /// <param name="presentation_time_delta"></param>
        /// <param name="timescale"></param>
        /// <param name="event_duration"></param>
        /// <param name="scte35payload"></param>
        private async void ScheduleAdFromScte35Payload(TimedMetadataTrack timedMetadataTrack, uint presentation_time_delta, uint timescale, uint event_duration, string scte35payload)
        {
            // TODO: Parse SCTE-35
            //
            // Ref:
            // http://www.scte.org/SCTEDocs/Standards/ANSI_SCTE%20214-3%202015.pdf
            //
            // Eg:
            //
            // <SpliceInfoSection ptsAdjustment="0" scte35:tier="4095">
            //  <SpliceInsert spliceEventId="147467497"
            //                spliceEventCancelIndicator="false"
            //                outOfNetworkIndicator="false"
            //                uniqueProgramId="0"
            //                availNum="0"
            //                availsExpected="0"
            //                spliceImmediateFlag="false" >
            //    <Program>
            //      <SpliceTime ptsTime="6257853600"/>
            //    </Program>
            //    <BreakDuration autoReturn="true" duration="900000"/>
            //  </SpliceInsert>
            // </SpliceInfoSection>
            //
            //

            // We use the metadata track object which fired the Cue to walk our way back up the
            // media object stack to find our original AdaptiveMediaSource.
            //
            // The AdaptiveMediaSource is required because the SCTE-35 payload includes
            // timing offsets which are relative to the original content PTS -- see below.
            var ams = timedMetadataTrack.PlaybackItem.Source.AdaptiveMediaSource;

            if (ams != null && timescale != 0)
            {
                // ++++
                // NOTE: DO NOT PARSE SCTE35 LIKE THIS IN PRODUCTION CODE!
                //
                // Reminder:
                //
                // THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
                // ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
                // IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
                // PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
                //
                // We will not demonstrate proper SCTE35 parsing in this sample,
                // but instead we search through the xml find the ptsTime if present,
                // and use it to schedule an ad; keeping in place the various time offsets.
                //
                // e.g.: var sampleScte35Payload = "<SpliceInfoSection ptsAdjustment=\"0\" scte35:tier=\"4095\">< SpliceInsert spliceEventId = \"147467497\" spliceEventCancelIndicator = \"false\" outOfNetworkIndicator = \"false\" uniqueProgramId = \"0\" availNum = \"0\" availsExpected = \"0\" spliceImmediateFlag = \"false\" > < Program >< SpliceTime ptsTime = \"6257853600\" /></ Program >  < BreakDuration autoReturn = \"true\" duration = \"900000\" />  </ SpliceInsert > </ SpliceInfoSection > ";
                //
                var    xmlStrings = scte35payload.Split(new string[] { "<", "/", ">", " ", "=", "\"" }, StringSplitOptions.RemoveEmptyEntries);
                string ptsTime    = string.Empty;
                for (int i = 0; i < xmlStrings.Length; i++)
                {
                    if (xmlStrings[i] == "ptsTime")
                    {
                        if (i + 1 < xmlStrings.Length)
                        {
                            ptsTime = xmlStrings[i + 1];
                            break;
                        }
                    }
                }
                // ----

                // The AdaptiveMediaSource keeps track of the original PTS in an AdaptiveMediaSourceCorrelatedTimes
                // object that can be retrieved via ams.GetCorrelatedTimes().  All the while, it provids the
                // media pipeline with a consistent timeline that re-aligns zero at the begining  of the SeekableRange
                // when first joining a Live stream.
                long pts = 0;
                long.TryParse(ptsTime, out pts);
                var timeCorrelation = ams.GetCorrelatedTimes();
                if (timeCorrelation.Position.HasValue && timeCorrelation.PresentationTimeStamp.HasValue)
                {
                    TimeSpan currentPosition;
                    await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                        currentPosition = mediaPlayerElement.MediaPlayer.PlaybackSession.Position;
                    });

                    TimeSpan emsgPresentationTimeDelta = TimeSpan.FromSeconds(presentation_time_delta / timescale);
                    long     delayInTicks            = timeCorrelation.PresentationTimeStamp.Value.Ticks - pts;
                    TimeSpan correctionForAsyncCalls = currentPosition - timeCorrelation.Position.Value;
                    TimeSpan targetAdPosition        = emsgPresentationTimeDelta + TimeSpan.FromTicks(delayInTicks) + correctionForAsyncCalls;

                    Log($"Timing Info: PlaybackSession.Position:{currentPosition}  targetAdPosition:{targetAdPosition}  Delta:{targetAdPosition-currentPosition}  Ams.Position:{timeCorrelation.Position.GetValueOrDefault().Ticks}  SCTE ptsTime:{pts}  emsgPresentationTimeDelta:{emsgPresentationTimeDelta} Ams.PresentationTimeStamp:{timeCorrelation.PresentationTimeStamp.GetValueOrDefault().Ticks}  Ams.ProgramDateTime:{timeCorrelation.ProgramDateTime.GetValueOrDefault()}");

                    MediaBreakInsertionMethod insertionMethod = ams.IsLive ? MediaBreakInsertionMethod.Replace : MediaBreakInsertionMethod.Interrupt;
                    var redSkyUri = new Uri("http://az29176.vo.msecnd.net/videocontent/RedSky_FoxRiverWisc_GettyImagesRF-499617760_1080_HD_EN-US.mp4");
                    if (targetAdPosition != TimeSpan.Zero && targetAdPosition >= currentPosition)
                    {
                        // Schedule ad in the future:
                        Log($"Ad insertion triggerd by 'emsg'.  Scheduled: {targetAdPosition.ToString()} Current:{currentPosition.ToString()}");
                        var midRollBreak = new MediaBreak(insertionMethod, targetAdPosition);
                        midRollBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)));
                        timedMetadataTrack.PlaybackItem.BreakSchedule.InsertMidrollBreak(midRollBreak);
                    }
                    else
                    {
                        // Play now!
                        Log($"Ad inserted immediately.  Scheduled: {targetAdPosition.ToString()} Current:{currentPosition.ToString()}");
                        var midRollBreak = new MediaBreak(insertionMethod);
                        midRollBreak.PlaybackList.Items.Add(new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri)));
                        await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                        {
                            mediaPlayerElement.MediaPlayer.BreakManager.PlayBreak(midRollBreak);
                        });
                    }
                }
            }
        }
        private void CreateMediaBreaksForItem(MediaPlaybackItem item)
        {
            if (item != null)
            {
                // We have two ads that will be repeated.
                var redSkyUri  = new Uri("http://az29176.vo.msecnd.net/videocontent/RedSky_FoxRiverWisc_GettyImagesRF-499617760_1080_HD_EN-US.mp4");
                var flowersUri = new Uri("http://az29176.vo.msecnd.net/videocontent/CrocusTL_FramePoolRM_688-580-676_1080_HD_EN-US.mp4");

                // One option is to create a separate MediaPlaybackItem for each of your ads.
                // You might choose to do this if each ad needs different reporting information.
                // Another option is to re-use MediaPlaybackItems in different MediaBreaks.
                // This scenario demonstrates both patterns.
                var ad1 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri));
                ad1.Source.CustomProperties["contentId"]   = "Ad1_ID";
                ad1.Source.CustomProperties["description"] = "Red Sky";
                ad1.Source.CustomProperties["uri"]         = redSkyUri.ToString();
                RegisterForMediaSourceEvents(ad1.Source);
                RegisterForMediaPlaybackItemEvents(ad1);

                var ad2 = new MediaPlaybackItem(MediaSource.CreateFromUri(flowersUri));
                ad2.Source.CustomProperties["contentId"]   = "Ad2_ID";
                ad2.Source.CustomProperties["description"] = "Flowers";
                ad2.Source.CustomProperties["uri"]         = flowersUri.ToString();
                RegisterForMediaSourceEvents(ad2.Source);
                RegisterForMediaPlaybackItemEvents(ad2);

                var ad3 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri));
                ad3.Source.CustomProperties["contentId"]   = "Ad3_ID";
                ad3.Source.CustomProperties["description"] = "Red Sky 2";
                ad3.Source.CustomProperties["uri"]         = redSkyUri.ToString();
                RegisterForMediaSourceEvents(ad3.Source);
                RegisterForMediaPlaybackItemEvents(ad3);

                // Create a PrerollBreak on your main content.
                if (item.BreakSchedule.PrerollBreak == null)
                {
                    item.BreakSchedule.PrerollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
                }

                // Add the ads to the PrerollBreak in the order you want them played
                item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad1);
                item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad2);

                // Add the ads to the MidRoll break at 10% into the main content.
                // To do this, we need to wait until the main MediaPlaybackItem is fully loaded by the player
                // so that we know its Duration. This will happen on MediaSource.OpenOperationCompleted.
                item.Source.OpenOperationCompleted += (sender, args) =>
                {
                    var attachedItem = MediaPlaybackItem.FindFromMediaSource(sender);
                    if (sender.Duration.HasValue)
                    {
                        // For live streaming, the duration will be TimeSpan.MaxValue, which won't work for this scenario,
                        // so we'll assume the total duration is 2 minutes for the purpose of ad insertion.
                        bool isLiveMediaSource   = item.Source.AdaptiveMediaSource != null ? item.Source.AdaptiveMediaSource.IsLive : false;
                        long sourceDurationTicks = isLiveMediaSource ? TimeSpan.FromMinutes(2).Ticks : sender.Duration.Value.Ticks;
                        var  positionAt10PercentOfMainContent = TimeSpan.FromTicks(sourceDurationTicks / 10);

                        // If the content is live, then the ad break replaces the streaming content.
                        // If the content is not live, then the content pauses for the ad, and then resumes
                        // after the ad is complete.
                        MediaBreakInsertionMethod insertionMethod = isLiveMediaSource ? MediaBreakInsertionMethod.Replace : MediaBreakInsertionMethod.Interrupt;
                        var midRollBreak = new MediaBreak(insertionMethod, positionAt10PercentOfMainContent);
                        midRollBreak.PlaybackList.Items.Add(ad2);
                        midRollBreak.PlaybackList.Items.Add(ad1);
                        attachedItem.BreakSchedule.InsertMidrollBreak(midRollBreak);
                        Log($"Added MidRoll at {positionAt10PercentOfMainContent}");
                    }
                };

                // Create a PostrollBreak:
                // Note: for Live content, it will only play once the presentation transitions to VOD.
                if (item.BreakSchedule.PostrollBreak == null)
                {
                    item.BreakSchedule.PostrollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
                }
                // Add the ads to the PostrollBreak in the order you want them played
                item.BreakSchedule.PostrollBreak.PlaybackList.Items.Add(ad3);
            }
        }
        private void CreateMediaBreaksForItem(MediaPlaybackItem item)
        {
            if (item != null)
            {
                // We have two ads that will be repeated.
                var redSkyUri = new Uri("http://az29176.vo.msecnd.net/videocontent/RedSky_FoxRiverWisc_GettyImagesRF-499617760_1080_HD_EN-US.mp4");
                var flowersUri = new Uri("http://az29176.vo.msecnd.net/videocontent/CrocusTL_FramePoolRM_688-580-676_1080_HD_EN-US.mp4");

                // One option is to create a separate MediaPlaybackItem for each of your ads.
                // You might choose to do this if each ad needs different reporting information.
                // Another option is to re-use MediaPlaybackItems in different MediaBreaks.
                // This scenario demonstrates both patterns.
                var ad1 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri));
                ad1.Source.CustomProperties["contentId"] = "Ad1_ID";
                ad1.Source.CustomProperties["description"] = "Red Sky";
                ad1.Source.CustomProperties["uri"] = redSkyUri.ToString();
                RegisterForMediaSourceEvents(ad1.Source);
                RegisterForMediaPlaybackItemEvents(ad1);

                var ad2 = new MediaPlaybackItem(MediaSource.CreateFromUri(flowersUri));
                ad2.Source.CustomProperties["contentId"] = "Ad2_ID";
                ad2.Source.CustomProperties["description"] = "Flowers";
                ad2.Source.CustomProperties["uri"] = flowersUri.ToString();
                RegisterForMediaSourceEvents(ad2.Source);
                RegisterForMediaPlaybackItemEvents(ad2);

                var ad3 = new MediaPlaybackItem(MediaSource.CreateFromUri(redSkyUri));
                ad3.Source.CustomProperties["contentId"] = "Ad3_ID";
                ad3.Source.CustomProperties["description"] = "Red Sky 2";
                ad3.Source.CustomProperties["uri"] = redSkyUri.ToString();
                RegisterForMediaSourceEvents(ad3.Source);
                RegisterForMediaPlaybackItemEvents(ad3);

                // Create a PrerollBreak on your main content.
                if (item.BreakSchedule.PrerollBreak == null)
                {
                    item.BreakSchedule.PrerollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
                }

                // Add the ads to the PrerollBreak in the order you want them played
                item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad1);
                item.BreakSchedule.PrerollBreak.PlaybackList.Items.Add(ad2);

                // Add the ads to the MidRoll break at 10% into the main content.
                // To do this, we need to wait until the main MediaPlaybackItem is fully loaded by the player
                // so that we know its Duration. This will happen on MediaSource.OpenOperationCompleted.
                item.Source.OpenOperationCompleted += (sender, args) =>
                {
                    var attachedItem = MediaPlaybackItem.FindFromMediaSource(sender);
                    if (sender.Duration.HasValue)
                    {
                        // For live streaming, the duration will be TimeSpan.MaxValue, which won't work for this scenario,
                        // so we'll assume the total duration is 2 minutes for the purpose of ad insertion.
                        long sourceDurationTicks = isLiveMediaSource ? TimeSpan.FromMinutes(2).Ticks : sender.Duration.Value.Ticks;
                        var positionAt10PercentOfMainContent = TimeSpan.FromTicks(sourceDurationTicks / 10);

                        // If the content is live, then the ad break replaces the streaming content.
                        // If the content is not live, then the content pauses for the ad, and then resumes
                        // after the ad is complete.
                        MediaBreakInsertionMethod insertionMethod = isLiveMediaSource ? MediaBreakInsertionMethod.Replace : MediaBreakInsertionMethod.Interrupt;
                        var midRollBreak = new MediaBreak(insertionMethod, positionAt10PercentOfMainContent);
                        midRollBreak.PlaybackList.Items.Add(ad2);
                        midRollBreak.PlaybackList.Items.Add(ad1);
                        attachedItem.BreakSchedule.InsertMidrollBreak(midRollBreak);
                        Log($"Added MidRoll at {positionAt10PercentOfMainContent}");
                    }
                };

                // Create a PostrollBreak:
                // Note: for Live content, it will only play once the presentation transitions to VOD.
                if (item.BreakSchedule.PostrollBreak == null)
                {
                    item.BreakSchedule.PostrollBreak = new MediaBreak(MediaBreakInsertionMethod.Interrupt);
                }
                // Add the ads to the PostrollBreak in the order you want them played
                item.BreakSchedule.PostrollBreak.PlaybackList.Items.Add(ad3);
            }
        }